From 7c7ebbb35f25cd19ba70bce3f390aea901e26491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 18 Feb 2020 14:11:02 +0100 Subject: [PATCH 001/165] [yul-phaser] main: Rename initializeRNG() to initialiseRNG() --- tools/yulPhaser/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 321ebe0881e9..e3464029c4f0 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -49,7 +49,7 @@ struct CommandLineParsingResult }; -void initializeRNG(po::variables_map const& arguments) +void initialiseRNG(po::variables_map const& arguments) { uint32_t seed; if (arguments.count("seed") > 0) @@ -156,7 +156,7 @@ int main(int argc, char** argv) if (parsingResult.exitCode != 0) return parsingResult.exitCode; - initializeRNG(parsingResult.arguments); + initialiseRNG(parsingResult.arguments); try { From 44932dc85a4fc20b4fbc1a27e1becfaffd7b130a Mon Sep 17 00:00:00 2001 From: cameel Date: Wed, 5 Feb 2020 14:56:55 +0100 Subject: [PATCH 002/165] [yul-phaser] Base class for pair selections --- tools/CMakeLists.txt | 2 ++ tools/yulPhaser/PairSelections.cpp | 18 ++++++++++ tools/yulPhaser/PairSelections.h | 53 ++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tools/yulPhaser/PairSelections.cpp create mode 100644 tools/yulPhaser/PairSelections.h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 21c0b8c913a6..b26fd166f3c9 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -23,6 +23,8 @@ add_executable(yul-phaser yulPhaser/FitnessMetrics.cpp yulPhaser/Chromosome.h yulPhaser/Chromosome.cpp + yulPhaser/PairSelections.h + yulPhaser/PairSelections.cpp yulPhaser/Selections.h yulPhaser/Selections.cpp yulPhaser/Program.h diff --git a/tools/yulPhaser/PairSelections.cpp b/tools/yulPhaser/PairSelections.cpp new file mode 100644 index 000000000000..6e63e4710b79 --- /dev/null +++ b/tools/yulPhaser/PairSelections.cpp @@ -0,0 +1,18 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include diff --git a/tools/yulPhaser/PairSelections.h b/tools/yulPhaser/PairSelections.h new file mode 100644 index 000000000000..c7e8339326d9 --- /dev/null +++ b/tools/yulPhaser/PairSelections.h @@ -0,0 +1,53 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains an abstract base class representing a selection of pairs of elements from a collection + * and its concrete implementations. + */ + +#pragma once + +#include +#include + +namespace solidity::phaser +{ + +/** + * Abstract base class for selections of pairs elements from a collection. + * + * An instance of this class represents a specific method of selecting a set of pairs of elements + * from containers of arbitrary sizes. The selected pairs always point at a subset of the elements + * from the container but may indicate the same element more than once. The pairs themselves can + * repeat too. The selection may or may not be fixed - it's up to a specific implementation whether + * subsequent calls for the same container produce the same indices or not. + * + * Derived classes are meant to override the @a materialise() method. + * This method is expected to produce pairs of selected elements given the size of the collection. + */ +class PairSelection +{ +public: + PairSelection() = default; + PairSelection(PairSelection const&) = delete; + PairSelection& operator=(PairSelection const&) = delete; + virtual ~PairSelection() = default; + + virtual std::vector> materialise(size_t _poolSize) const = 0; +}; + +} From f9f2bdb5f7d4565637b8c22cffe8f3666502bd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 6 Feb 2020 04:36:46 +0100 Subject: [PATCH 003/165] [yul-phaser] Add RandomPairSelection and PairMosaicSelection classes --- test/CMakeLists.txt | 2 + test/yulPhaser/PairSelections.cpp | 185 +++++++++++++++++++++++++++++ tools/yulPhaser/PairSelections.cpp | 47 ++++++++ tools/yulPhaser/PairSelections.h | 46 +++++++ 4 files changed, 280 insertions(+) create mode 100644 test/yulPhaser/PairSelections.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ea080686771..2fcbb2fafff6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -145,6 +145,7 @@ set(yul_phaser_sources yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp yulPhaser/GeneticAlgorithms.cpp + yulPhaser/PairSelections.cpp yulPhaser/Population.cpp yulPhaser/Program.cpp yulPhaser/Selections.cpp @@ -156,6 +157,7 @@ set(yul_phaser_sources ../tools/yulPhaser/Chromosome.cpp ../tools/yulPhaser/FitnessMetrics.cpp ../tools/yulPhaser/GeneticAlgorithms.cpp + ../tools/yulPhaser/PairSelections.cpp ../tools/yulPhaser/Population.cpp ../tools/yulPhaser/Program.cpp ../tools/yulPhaser/Selections.cpp diff --git a/test/yulPhaser/PairSelections.cpp b/test/yulPhaser/PairSelections.cpp new file mode 100644 index 000000000000..af03cd2bcae6 --- /dev/null +++ b/test/yulPhaser/PairSelections.cpp @@ -0,0 +1,185 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include + +#include + +#include +#include +#include + +using namespace std; + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(PairSelectionsTest) +BOOST_AUTO_TEST_SUITE(RandomPairSelectionTest) + +BOOST_AUTO_TEST_CASE(materialise_should_return_random_values_with_equal_probabilities) +{ + constexpr int collectionSize = 10; + constexpr int selectionSize = 100; + constexpr double relativeTolerance = 0.1; + constexpr double expectedValue = (collectionSize - 1) / 2.0; + constexpr double variance = (collectionSize * collectionSize - 1) / 12.0; + + SimulationRNG::reset(1); + vector> pairs = RandomPairSelection(selectionSize).materialise(collectionSize); + vector samples; + for (auto& [first, second]: pairs) + { + samples.push_back(first); + samples.push_back(second); + } + + BOOST_TEST(abs(mean(samples) - expectedValue) < expectedValue * relativeTolerance); + BOOST_TEST(abs(meanSquaredError(samples, expectedValue) - variance) < variance * relativeTolerance); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_only_values_that_can_be_used_as_collection_indices) +{ + const size_t collectionSize = 200; + + vector> pairs = RandomPairSelection(0.5).materialise(collectionSize); + + BOOST_TEST(pairs.size() == 100); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [&](auto const& pair){ return get<0>(pair) <= collectionSize; })); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [&](auto const& pair){ return get<1>(pair) <= collectionSize; })); +} + +BOOST_AUTO_TEST_CASE(materialise_should_never_return_a_pair_of_identical_indices) +{ + vector> pairs = RandomPairSelection(0.5).materialise(100); + + BOOST_TEST(pairs.size() == 50); + BOOST_TEST(all_of(pairs.begin(), pairs.end(), [](auto const& pair){ return get<0>(pair) != get<1>(pair); })); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_number_of_pairs_thats_a_fraction_of_collection_size) +{ + BOOST_TEST(RandomPairSelection(0.0).materialise(10).size() == 0); + BOOST_TEST(RandomPairSelection(0.3).materialise(10).size() == 3); + BOOST_TEST(RandomPairSelection(0.5).materialise(10).size() == 5); + BOOST_TEST(RandomPairSelection(0.7).materialise(10).size() == 7); + BOOST_TEST(RandomPairSelection(1.0).materialise(10).size() == 10); +} + +BOOST_AUTO_TEST_CASE(materialise_should_support_number_of_pairs_bigger_than_collection_size) +{ + BOOST_TEST(RandomPairSelection(2.0).materialise(5).size() == 10); + BOOST_TEST(RandomPairSelection(1.5).materialise(10).size() == 15); + BOOST_TEST(RandomPairSelection(10.0).materialise(10).size() == 100); +} + +BOOST_AUTO_TEST_CASE(materialise_should_round_the_number_of_pairs_to_the_nearest_integer) +{ + BOOST_TEST(RandomPairSelection(0.49).materialise(3).size() == 1); + BOOST_TEST(RandomPairSelection(0.50).materialise(3).size() == 2); + BOOST_TEST(RandomPairSelection(0.51).materialise(3).size() == 2); + + BOOST_TEST(RandomPairSelection(1.51).materialise(3).size() == 5); + + BOOST_TEST(RandomPairSelection(0.01).materialise(2).size() == 0); + BOOST_TEST(RandomPairSelection(0.01).materialise(3).size() == 0); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_is_empty) +{ + BOOST_TEST(RandomPairSelection(0).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(0.5).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(1.0).materialise(0).empty()); + BOOST_TEST(RandomPairSelection(2.0).materialise(0).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_has_one_element) +{ + BOOST_TEST(RandomPairSelection(0).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(0.5).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(1.0).materialise(1).empty()); + BOOST_TEST(RandomPairSelection(2.0).materialise(1).empty()); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(PairMosaicSelectionTest) + +using IndexPairs = vector>; + +BOOST_AUTO_TEST_CASE(materialise) +{ + BOOST_TEST(PairMosaicSelection({{1, 1}}, 0.5).materialise(4) == IndexPairs({{1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(4) == IndexPairs({{1, 1}, {1, 1}, {1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 2.0).materialise(4) == IndexPairs({{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}})); + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(2) == IndexPairs({{1, 1}, {1, 1}})); + + IndexPairs pairs1{{0, 1}, {1, 0}}; + BOOST_TEST(PairMosaicSelection(pairs1, 0.5).materialise(4) == IndexPairs({{0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 1.0).materialise(4) == IndexPairs({{0, 1}, {1, 0}, {0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 2.0).materialise(4) == IndexPairs({{0, 1}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}, {0, 1}, {1, 0}})); + BOOST_TEST(PairMosaicSelection(pairs1, 1.0).materialise(2) == IndexPairs({{0, 1}, {1, 0}})); + + IndexPairs pairs2{{3, 2}, {2, 3}, {1, 0}, {1, 1}}; + BOOST_TEST(PairMosaicSelection(pairs2, 0.5).materialise(4) == IndexPairs({{3, 2}, {2, 3}})); + BOOST_TEST(PairMosaicSelection(pairs2, 1.0).materialise(4) == IndexPairs({{3, 2}, {2, 3}, {1, 0}, {1, 1}})); + BOOST_TEST(PairMosaicSelection(pairs2, 2.0).materialise(4) == IndexPairs({{3, 2}, {2, 3}, {1, 0}, {1, 1}, {3, 2}, {2, 3}, {1, 0}, {1, 1}})); + + IndexPairs pairs3{{1, 0}, {1, 1}, {1, 0}, {1, 1}}; + BOOST_TEST(PairMosaicSelection(pairs3, 1.0).materialise(2) == IndexPairs({{1, 0}, {1, 1}})); +} + +BOOST_AUTO_TEST_CASE(materialise_should_round_indices) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 0.49).materialise(5) == IndexPairs({{4, 4}, {3, 3}})); + BOOST_TEST(PairMosaicSelection(pairs, 0.50).materialise(5) == IndexPairs({{4, 4}, {3, 3}, {2, 2}})); + BOOST_TEST(PairMosaicSelection(pairs, 0.51).materialise(5) == IndexPairs({{4, 4}, {3, 3}, {2, 2}})); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_is_empty) +{ + BOOST_TEST(PairMosaicSelection({{1, 1}}, 1.0).materialise(0).empty()); + BOOST_TEST(PairMosaicSelection({{1, 1}, {3, 3}}, 2.0).materialise(0).empty()); + BOOST_TEST(PairMosaicSelection({{5, 5}, {4, 4}, {3, 3}, {2, 2}}, 0.5).materialise(0).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_return_no_pairs_if_collection_has_one_element) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 0.0).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 0.5).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 1.0).materialise(1).empty()); + BOOST_TEST(PairMosaicSelection(pairs, 7.0).materialise(1).empty()); +} + +BOOST_AUTO_TEST_CASE(materialise_should_clamp_indices_at_collection_size) +{ + IndexPairs pairs{{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + BOOST_TEST(PairMosaicSelection(pairs, 1.0).materialise(4) == IndexPairs({{3, 3}, {3, 3}, {2, 2}, {1, 1}})); + BOOST_TEST(PairMosaicSelection(pairs, 2.0).materialise(3) == IndexPairs({{2, 2}, {2, 2}, {2, 2}, {1, 1}, {0, 0}, {2, 2}})); + +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/tools/yulPhaser/PairSelections.cpp b/tools/yulPhaser/PairSelections.cpp index 6e63e4710b79..8f3fd0f7f3c1 100644 --- a/tools/yulPhaser/PairSelections.cpp +++ b/tools/yulPhaser/PairSelections.cpp @@ -16,3 +16,50 @@ */ #include + +#include + +#include + +using namespace std; +using namespace solidity::phaser; + +vector> RandomPairSelection::materialise(size_t _poolSize) const +{ + if (_poolSize < 2) + return {}; + + size_t count = static_cast(round(_poolSize * m_selectionSize)); + + vector> selection; + for (size_t i = 0; i < count; ++i) + { + size_t index1 = SimulationRNG::uniformInt(0, _poolSize - 1); + size_t index2; + do + { + index2 = SimulationRNG::uniformInt(0, _poolSize - 1); + } while (index1 == index2); + + selection.push_back({index1, index2}); + } + + return selection; +} + +vector> PairMosaicSelection::materialise(size_t _poolSize) const +{ + if (_poolSize < 2) + return {}; + + size_t count = static_cast(round(_poolSize * m_selectionSize)); + + vector> selection; + for (size_t i = 0; i < count; ++i) + { + tuple pair = m_pattern[i % m_pattern.size()]; + selection.push_back({min(get<0>(pair), _poolSize - 1), min(get<1>(pair), _poolSize - 1)}); + } + + return selection; +} diff --git a/tools/yulPhaser/PairSelections.h b/tools/yulPhaser/PairSelections.h index c7e8339326d9..7778d656783a 100644 --- a/tools/yulPhaser/PairSelections.h +++ b/tools/yulPhaser/PairSelections.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -50,4 +51,49 @@ class PairSelection virtual std::vector> materialise(size_t _poolSize) const = 0; }; +/** + * A selection that selects pairs of random elements from a container. The resulting set of pairs + * may contain the same pair more than once but does not contain pairs of duplicates. Always + * selects as many pairs as the size of the container multiplied by @a _selectionSize (unless the + * container is empty). + */ +class RandomPairSelection: public PairSelection +{ +public: + explicit RandomPairSelection(double _selectionSize): + m_selectionSize(_selectionSize) {} + + std::vector> materialise(size_t _poolSize) const override; + +private: + double m_selectionSize; +}; + +/** + * A selection that selects pairs of elements at specific, fixed positions indicated by a repeating + * "pattern". If the positions in the pattern exceed the size of the container, they are capped at + * the maximum available position. Always selects as many pairs as the size of the container + * multiplied by @a _selectionSize (unless the container is empty). + * + * E.g. if the pattern is {{0, 1}, {3, 9}} and collection size is 5, the selection will materialise + * into {{0, 1}, {3, 4}, {0, 1}, {3, 4}, {0, 1}}. If the size is 3, it will be + * {{0, 1}, {2, 2}, {0, 1}}. + */ +class PairMosaicSelection: public PairSelection +{ +public: + explicit PairMosaicSelection(std::vector> _pattern, double _selectionSize = 1.0): + m_pattern(move(_pattern)), + m_selectionSize(_selectionSize) + { + assert(m_pattern.size() > 0 || _selectionSize == 0.0); + } + + std::vector> materialise(size_t _poolSize) const override; + +private: + std::vector> m_pattern; + double m_selectionSize; +}; + } From 643a5f2035ff8711dd4494c61a4444bd58501fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 14 Feb 2020 20:23:17 +0100 Subject: [PATCH 004/165] [yul-phaser] Common: Add wholeChromosomeReplacement() mutation and countDifferences() --- test/yulPhaser/Common.cpp | 15 +++++++++++++++ test/yulPhaser/Common.h | 12 ++++++++++++ test/yulPhaser/CommonTest.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp index 93aa432fa996..52cde95900af 100644 --- a/test/yulPhaser/Common.cpp +++ b/test/yulPhaser/Common.cpp @@ -24,6 +24,12 @@ using namespace std; using namespace solidity; using namespace solidity::yul; +using namespace solidity::phaser; + +function phaser::test::wholeChromosomeReplacement(Chromosome _newChromosome) +{ + return [_newChromosome = move(_newChromosome)](Chromosome const&) { return _newChromosome; }; +} vector phaser::test::chromosomeLengths(Population const& _population) { @@ -44,6 +50,15 @@ map phaser::test::enumerateOptmisationSteps() return stepIndices; } +size_t phaser::test::countDifferences(Chromosome const& _chromosome1, Chromosome const& _chromosome2) +{ + size_t count = 0; + for (size_t i = 0; i < min(_chromosome1.length(), _chromosome2.length()); ++i) + count += static_cast(_chromosome1.optimisationSteps()[i] != _chromosome2.optimisationSteps()[i]); + + return count + abs(static_cast(_chromosome1.length() - _chromosome2.length())); +} + string phaser::test::stripWhitespace(string const& input) { regex whitespaceRegex("\\s+"); diff --git a/test/yulPhaser/Common.h b/test/yulPhaser/Common.h index e73260d7adb7..cbec90f7883a 100644 --- a/test/yulPhaser/Common.h +++ b/test/yulPhaser/Common.h @@ -30,9 +30,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -52,11 +54,21 @@ class ChromosomeLengthMetric: public FitnessMetric size_t evaluate(Chromosome const& _chromosome) const override { return _chromosome.length(); } }; +// MUTATIONS + +/// Mutation that always replaces the whole chromosome with the one specified in the parameter. +std::function wholeChromosomeReplacement(Chromosome _newChromosome); + // CHROMOSOME AND POPULATION HELPERS /// Returns a vector containing lengths of all chromosomes in the population (in the same order). std::vector chromosomeLengths(Population const& _population); +/// Returns the number of genes that differ between two chromosomes. +/// If the chromnosomes have different lengths, the positions that are present in only one of them +/// are counted as mismatches. +size_t countDifferences(Chromosome const& _chromosome1, Chromosome const& _chromosome2); + /// Assigns indices from 0 to N to all optimisation steps available in the OptimiserSuite. /// This is a convenience helper to make it easier to test their distribution with tools made for /// integers. diff --git a/test/yulPhaser/CommonTest.cpp b/test/yulPhaser/CommonTest.cpp index 9bcab992314f..3456a66404bf 100644 --- a/test/yulPhaser/CommonTest.cpp +++ b/test/yulPhaser/CommonTest.cpp @@ -40,6 +40,12 @@ BOOST_AUTO_TEST_CASE(ChromosomeLengthMetric_evaluate_should_return_chromosome_le BOOST_TEST(ChromosomeLengthMetric{}.evaluate(Chromosome("aaaaa")) == 5); } +BOOST_AUTO_TEST_CASE(wholeChromosomeReplacement_should_replace_whole_chromosome_with_another) +{ + function mutation = wholeChromosomeReplacement(Chromosome("aaa")); + BOOST_TEST(mutation(Chromosome("ccc")) == Chromosome("aaa")); +} + BOOST_AUTO_TEST_CASE(chromosomeLengths_should_return_lengths_of_all_chromosomes_in_a_population) { shared_ptr fitnessMetric = make_shared(); @@ -51,6 +57,34 @@ BOOST_AUTO_TEST_CASE(chromosomeLengths_should_return_lengths_of_all_chromosomes_ BOOST_TEST((chromosomeLengths(population2) == vector{})); } +BOOST_AUTO_TEST_CASE(countDifferences_should_return_zero_for_identical_chromosomes) +{ + BOOST_TEST(countDifferences(Chromosome(), Chromosome()) == 0); + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("a")) == 0); + BOOST_TEST(countDifferences(Chromosome("afxT"), Chromosome("afxT")) == 0); +} + +BOOST_AUTO_TEST_CASE(countDifferences_should_count_mismatched_positions_in_chromosomes_of_the_same_length) +{ + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("f")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("ac")) == 1); + BOOST_TEST(countDifferences(Chromosome("ac"), Chromosome("cc")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("cc")) == 2); + BOOST_TEST(countDifferences(Chromosome("afxT"), Chromosome("Txfa")) == 4); +} + +BOOST_AUTO_TEST_CASE(countDifferences_should_count_missing_characters_as_differences) +{ + BOOST_TEST(countDifferences(Chromosome(""), Chromosome("a")) == 1); + BOOST_TEST(countDifferences(Chromosome("a"), Chromosome("")) == 1); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("")) == 2); + BOOST_TEST(countDifferences(Chromosome("aaa"), Chromosome("")) == 3); + + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("aaaa")) == 2); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("aacc")) == 2); + BOOST_TEST(countDifferences(Chromosome("aa"), Chromosome("cccc")) == 4); +} + BOOST_AUTO_TEST_CASE(enumerateOptimisationSteps_should_assing_indices_to_all_available_optimisation_steps) { map stepsAndAbbreviations = OptimiserSuite::stepNameToAbbreviationMap(); From 3fdb4ca607f6fb8ae069e96c246e16fce0f8f7c1 Mon Sep 17 00:00:00 2001 From: cameel Date: Wed, 5 Feb 2020 14:42:38 +0100 Subject: [PATCH 005/165] [yul-phaser] Add geneRandomisation(), geneDeletion(), geneAddition and alternativeMutations() --- test/CMakeLists.txt | 1 + test/yulPhaser/Mutations.cpp | 219 ++++++++++++++++++++++++++++++++++ tools/CMakeLists.txt | 2 + tools/yulPhaser/Mutations.cpp | 91 ++++++++++++++ tools/yulPhaser/Mutations.h | 56 +++++++++ 5 files changed, 369 insertions(+) create mode 100644 test/yulPhaser/Mutations.cpp create mode 100644 tools/yulPhaser/Mutations.cpp create mode 100644 tools/yulPhaser/Mutations.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2fcbb2fafff6..eb4b8241c1fd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -145,6 +145,7 @@ set(yul_phaser_sources yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp yulPhaser/GeneticAlgorithms.cpp + yulPhaser/Mutations.cpp yulPhaser/PairSelections.cpp yulPhaser/Population.cpp yulPhaser/Program.cpp diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp new file mode 100644 index 000000000000..29a516919691 --- /dev/null +++ b/test/yulPhaser/Mutations.cpp @@ -0,0 +1,219 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include + +#include +#include + +using namespace std; + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(MutationsTest) +BOOST_AUTO_TEST_SUITE(GeneRandomisationTest) + +BOOST_AUTO_TEST_CASE(geneRandomisation_should_iterate_over_genes_and_replace_them_with_random_ones_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneRandomisation(0.1); + function mutation05 = geneRandomisation(0.5); + function mutation10 = geneRandomisation(1.0); + + SimulationRNG::reset(1); + BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 2); + BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 5); + BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 7); + SimulationRNG::reset(2); + BOOST_TEST(countDifferences(mutation01(chromosome), chromosome), 1); + BOOST_TEST(countDifferences(mutation05(chromosome), chromosome), 3); + BOOST_TEST(countDifferences(mutation10(chromosome), chromosome), 9); +} + +BOOST_AUTO_TEST_CASE(geneRandomisation_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneRandomisation(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_iterate_over_genes_and_delete_them_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneDeletion(0.1); + function mutation05 = geneDeletion(0.5); + + SimulationRNG::reset(1); + // fcCUnDvejs + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcCU Dvejs"))); + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" D ejs"))); + SimulationRNG::reset(2); + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace("fcUnDvejs"))); + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace(" Un s"))); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneDeletion(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneDeletion_should_delete_all_genes_if_probability_is_one) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneDeletion(1.0); + + BOOST_TEST(mutation(chromosome) == Chromosome("")); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_iterate_over_gene_positions_and_insert_new_genes_with_given_probability) +{ + Chromosome chromosome("fcCUnDvejs"); + function mutation01 = geneAddition(0.1); + function mutation05 = geneAddition(0.5); + + SimulationRNG::reset(1); + // f c C U n D v e j s + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f c C UC n D v e jx s"))); // 20% more + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("j f cu C U ne D v eI j sf"))); // 50% more + SimulationRNG::reset(2); + BOOST_TEST(mutation01(chromosome) == Chromosome(stripWhitespace(" f cu C U n D v e j s"))); // 10% more + BOOST_TEST(mutation05(chromosome) == Chromosome(stripWhitespace("L f ce Cv U n D v e jO s"))); // 40% more +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_before_first_position) +{ + SimulationRNG::reset(7); + Chromosome chromosome("fcCUnDvejs"); + function mutation = geneAddition(0.1); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() > chromosome.length()); + + vector suffix( + mutatedChromosome.optimisationSteps().end() - chromosome.length(), + mutatedChromosome.optimisationSteps().end() + ); + BOOST_TEST(suffix == chromosome.optimisationSteps()); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_be_able_to_insert_after_last_position) +{ + SimulationRNG::reset(81); + Chromosome chromosome("fcCUnDvejs"); + function mutation = geneAddition(0.1); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() > chromosome.length()); + + vector prefix( + mutatedChromosome.optimisationSteps().begin(), + mutatedChromosome.optimisationSteps().begin() + chromosome.length() + ); + BOOST_TEST(prefix == chromosome.optimisationSteps()); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_return_identical_chromosome_if_probability_is_zero) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneAddition(0.0); + + BOOST_TEST(mutation(chromosome) == chromosome); +} + +BOOST_AUTO_TEST_CASE(geneAddition_should_insert_genes_at_all_positions_if_probability_is_one) +{ + Chromosome chromosome("fcCUnDvejsrmV"); + function mutation = geneAddition(1.0); + + Chromosome mutatedChromosome = mutation(chromosome); + BOOST_TEST(mutatedChromosome.length() == chromosome.length() * 2 + 1); + + vector originalGenes; + for (size_t i = 0; i < mutatedChromosome.length() - 1; ++i) + if (i % 2 == 1) + originalGenes.push_back(mutatedChromosome.optimisationSteps()[i]); + + BOOST_TEST(Chromosome(originalGenes) == chromosome); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_choose_between_mutations_with_given_probability) +{ + SimulationRNG::reset(1); + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 0.8, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + size_t cCount = 0; + size_t fCount = 0; + for (size_t i = 0; i < 10; ++i) + { + Chromosome mutatedChromosome = mutation(chromosome); + cCount += static_cast(mutatedChromosome == Chromosome("c")); + fCount += static_cast(mutatedChromosome == Chromosome("f")); + } + + // This particular seed results in 7 "c"s out of 10 which looks plausible given the 80% chance. + BOOST_TEST(cCount == 7); + BOOST_TEST(fCount == 3); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_first_mutation_if_probability_is_one) +{ + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 1.0, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + for (size_t i = 0; i < 10; ++i) + BOOST_TEST(mutation(chromosome) == Chromosome("c")); +} + +BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_second_mutation_if_probability_is_zero) +{ + Chromosome chromosome("a"); + function mutation = alternativeMutations( + 0.0, + wholeChromosomeReplacement(Chromosome("c")), + wholeChromosomeReplacement(Chromosome("f")) + ); + + for (size_t i = 0; i < 10; ++i) + BOOST_TEST(mutation(chromosome) == Chromosome("f")); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b26fd166f3c9..4791087b52f8 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -23,6 +23,8 @@ add_executable(yul-phaser yulPhaser/FitnessMetrics.cpp yulPhaser/Chromosome.h yulPhaser/Chromosome.cpp + yulPhaser/Mutations.h + yulPhaser/Mutations.cpp yulPhaser/PairSelections.h yulPhaser/PairSelections.cpp yulPhaser/Selections.h diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp new file mode 100644 index 000000000000..4010f89d3d8e --- /dev/null +++ b/tools/yulPhaser/Mutations.cpp @@ -0,0 +1,91 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::phaser; + +function phaser::geneRandomisation(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + for (auto const& step: _chromosome.optimisationSteps()) + optimisationSteps.push_back( + SimulationRNG::bernoulliTrial(_chance) ? + Chromosome::randomOptimisationStep() : + step + ); + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::geneDeletion(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + for (auto const& step: _chromosome.optimisationSteps()) + if (!SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(step); + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::geneAddition(double _chance) +{ + return [=](Chromosome const& _chromosome) + { + vector optimisationSteps; + + if (SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + + for (auto const& step: _chromosome.optimisationSteps()) + { + optimisationSteps.push_back(step); + if (SimulationRNG::bernoulliTrial(_chance)) + optimisationSteps.push_back(Chromosome::randomOptimisationStep()); + } + + return Chromosome(move(optimisationSteps)); + }; +} + +function phaser::alternativeMutations( + double _firstMutationChance, + function _mutation1, + function _mutation2 +) +{ + return [=](Chromosome const& _chromosome) + { + if (SimulationRNG::bernoulliTrial(_firstMutationChance)) + return _mutation1(_chromosome); + else + return _mutation2(_chromosome); + }; +} diff --git a/tools/yulPhaser/Mutations.h b/tools/yulPhaser/Mutations.h new file mode 100644 index 000000000000..b18f195ef157 --- /dev/null +++ b/tools/yulPhaser/Mutations.h @@ -0,0 +1,56 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Mutation and crossover operators for use in genetic algorithms. + */ + +#pragma once + +#include + +#include + +namespace solidity::phaser +{ + +using Mutation = Chromosome(Chromosome const&); + +// MUTATIONS + +/// Creates a mutation operator that iterates over all genes in a chromosome and with probability +/// @a _chance replaces a gene with a random one (which could also be the same as the original). +std::function geneRandomisation(double _chance); + +/// Creates a mutation operator that iterates over all genes in a chromosome and with probability +/// @a _chance deletes it. +std::function geneDeletion(double _chance); + +/// Creates a mutation operator that iterates over all positions in a chromosome (including spots +/// at the beginning and at the end of the sequence) and with probability @a _chance insert a new, +/// randomly chosen gene. +std::function geneAddition(double _chance); + +/// Creates a mutation operator that always applies one of the mutations passed to it. +/// The probability that the chosen mutation is the first one is @a _firstMutationChance. +/// randomly chosen gene. +std::function alternativeMutations( + double _firstMutationChance, + std::function _mutation1, + std::function _mutation2 +); + +} From c941eaf5d68f488137f4e1d2f3dbf31d2de30634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 6 Feb 2020 04:34:09 +0100 Subject: [PATCH 006/165] [yul-phaser] Add randomPointCrossover() and fixedPointCrossover() operators --- test/yulPhaser/Mutations.cpp | 156 ++++++++++++++++++++++++++++++++++ tools/yulPhaser/Mutations.cpp | 62 ++++++++++++++ tools/yulPhaser/Mutations.h | 20 +++++ 3 files changed, 238 insertions(+) diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index 29a516919691..49f6e7f0224d 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -212,6 +212,162 @@ BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_second_mutation_i BOOST_TEST(mutation(chromosome) == Chromosome("f")); } +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_swap_chromosome_parts_at_random_point) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + auto [result1, result2] = crossover(Chromosome("aaaaaaaaaa"), Chromosome("cccccc")); + BOOST_TEST(result1 == Chromosome("aaaccc")); + BOOST_TEST(result2 == Chromosome("cccaaaaaaa")); +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_only_consider_points_available_on_both_chromosomes) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + auto [result1, result2] = crossover(Chromosome("aaa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + BOOST_TEST(( + (result1 == Chromosome("TTTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("aaa")) || + (result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("Taa")) || + (result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTa")) || + (result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTT")) + )); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if_chromosomes_are_splittable) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + auto [result1, result2] = crossover(Chromosome("aa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + BOOST_TEST(result1 != Chromosome("TTTTTTTTTTTTTTTTTTTT")); + BOOST_TEST(result2 != Chromosome("aa")); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if_chromosomes_are_not_empty) +{ + SimulationRNG::reset(1); + function crossover = randomPointCrossover(); + + for (size_t i = 0; i < 30; ++i) + { + auto [result1, result2] = crossover(Chromosome("a"), Chromosome("T")); + BOOST_TEST(result1 == Chromosome("a")); + BOOST_TEST(result2 == Chromosome("T")); + } +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_work_even_if_one_chromosome_is_unsplittable) +{ + function crossover = randomPointCrossover(); + + SimulationRNG::reset(1); + BOOST_CHECK(crossover(Chromosome("ff"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("af"))); + BOOST_CHECK(crossover(Chromosome("a"), Chromosome("ff")) == ChromosomePair(Chromosome("af"), Chromosome("f"))); +} + +BOOST_AUTO_TEST_CASE(randomPointCrossover_should_split_at_position_zero_only_if_at_least_one_chromosome_is_empty) +{ + Chromosome empty(""); + Chromosome unsplittable("a"); + Chromosome splittable("aaaa"); + function crossover = randomPointCrossover(); + + SimulationRNG::reset(1); + BOOST_CHECK(crossover(empty, empty) == ChromosomePair(empty, empty)); + BOOST_CHECK(crossover(unsplittable, empty) == ChromosomePair(empty, unsplittable)); + BOOST_CHECK(crossover(empty, unsplittable) == ChromosomePair(unsplittable, empty)); + BOOST_CHECK(crossover(splittable, empty) == ChromosomePair(empty, splittable)); + BOOST_CHECK(crossover(empty, splittable) == ChromosomePair(splittable, empty)); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_swap_chromosome_parts_at_given_point) +{ + auto [result1, result2] = fixedPointCrossover(0.8)(Chromosome("aaaaaaaaaa"), Chromosome("cccccccccc")); + BOOST_TEST(result1 == Chromosome("aaaaaaaacc")); + BOOST_TEST(result2 == Chromosome("ccccccccaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_determine_crossover_point_based_on_length_of_shorter_chromosome) +{ + auto [result1, result2] = fixedPointCrossover(0.4)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + BOOST_TEST(result1 == Chromosome("aacccccccc")); + BOOST_TEST(result2 == Chromosome("ccaaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_round_split_point) +{ + auto [result1, result2] = fixedPointCrossover(0.49)(Chromosome("aaaaa"), Chromosome("ccccc")); + BOOST_TEST(result1 == Chromosome("aaccc")); + BOOST_TEST(result2 == Chromosome("ccaaa")); + + auto [result3, result4] = fixedPointCrossover(0.50)(Chromosome("aaaaa"), Chromosome("ccccc")); + BOOST_TEST(result3 == Chromosome("aaacc")); + BOOST_TEST(result4 == Chromosome("cccaa")); + + auto [result5, result6] = fixedPointCrossover(0.51)(Chromosome("aaaaa"), Chromosome("ccccc")); + BOOST_TEST(result5 == Chromosome("aaacc")); + BOOST_TEST(result6 == Chromosome("cccaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_position_zero_if_explicitly_requested) +{ + auto [result1, result2] = fixedPointCrossover(0.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + BOOST_TEST(result1 == Chromosome("cccccccccc")); + BOOST_TEST(result2 == Chromosome("aaaaa")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_end_of_shorter_chromosome_if_crossover_point_is_after_last_position) +{ + auto [result1, result2] = fixedPointCrossover(1.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + BOOST_TEST(result1 == Chromosome("aaaaaccccc")); + BOOST_TEST(result2 == Chromosome("ccccc")); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_select_correct_split_point_for_unsplittable_chromosomes) +{ + function crossover00 = fixedPointCrossover(0.0); + BOOST_CHECK(crossover00(Chromosome("fff"), Chromosome("a")) == ChromosomePair(Chromosome("a"), Chromosome("fff"))); + BOOST_CHECK(crossover00(Chromosome("a"), Chromosome("fff")) == ChromosomePair(Chromosome("fff"), Chromosome("a"))); + + BOOST_CHECK(crossover00(Chromosome("f"), Chromosome("a")) == ChromosomePair(Chromosome("a"), Chromosome("f"))); + + function crossover10 = fixedPointCrossover(1.0); + BOOST_CHECK(crossover10(Chromosome("fff"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("aff"))); + BOOST_CHECK(crossover10(Chromosome("a"), Chromosome("fff")) == ChromosomePair(Chromosome("aff"), Chromosome("f"))); + + BOOST_CHECK(crossover10(Chromosome("f"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("a"))); +} + +BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_always_use_position_zero_as_split_point_when_chromosome_empty) +{ + Chromosome empty(""); + Chromosome unsplittable("f"); + Chromosome splittable("aaaa"); + + function crossover00 = fixedPointCrossover(0.0); + BOOST_CHECK(crossover00(empty, empty) == ChromosomePair(empty, empty)); + BOOST_CHECK(crossover00(unsplittable, empty) == ChromosomePair(empty, unsplittable)); + BOOST_CHECK(crossover00(empty, unsplittable) == ChromosomePair(unsplittable, empty)); + BOOST_CHECK(crossover00(splittable, empty) == ChromosomePair(empty, splittable)); + BOOST_CHECK(crossover00(empty, splittable) == ChromosomePair(splittable, empty)); + + function crossover10 = fixedPointCrossover(1.0); + BOOST_CHECK(crossover10(empty, empty) == ChromosomePair(empty, empty)); + BOOST_CHECK(crossover10(unsplittable, empty) == ChromosomePair(empty, unsplittable)); + BOOST_CHECK(crossover10(empty, unsplittable) == ChromosomePair(unsplittable, empty)); + BOOST_CHECK(crossover10(splittable, empty) == ChromosomePair(empty, splittable)); + BOOST_CHECK(crossover10(empty, splittable) == ChromosomePair(splittable, empty)); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp index 4010f89d3d8e..f639d8f6afb1 100644 --- a/tools/yulPhaser/Mutations.cpp +++ b/tools/yulPhaser/Mutations.cpp @@ -19,6 +19,11 @@ #include +#include + +#include +#include +#include #include #include @@ -89,3 +94,60 @@ function phaser::alternativeMutations( return _mutation2(_chromosome); }; } + +namespace +{ + +ChromosomePair buildChromosomesBySwappingParts( + Chromosome const& _chromosome1, + Chromosome const& _chromosome2, + size_t _crossoverPoint +) +{ + assert(_crossoverPoint <= _chromosome1.length()); + assert(_crossoverPoint <= _chromosome2.length()); + + auto begin1 = _chromosome1.optimisationSteps().begin(); + auto begin2 = _chromosome2.optimisationSteps().begin(); + + return ChromosomePair( + Chromosome( + vector(begin1, begin1 + _crossoverPoint) + + vector(begin2 + _crossoverPoint, _chromosome2.optimisationSteps().end()) + ), + Chromosome( + vector(begin2, begin2 + _crossoverPoint) + + vector(begin1 + _crossoverPoint, _chromosome1.optimisationSteps().end()) + ) + ); +} + +} + +function phaser::randomPointCrossover() +{ + return [=](Chromosome const& _chromosome1, Chromosome const& _chromosome2) + { + size_t minLength = min(_chromosome1.length(), _chromosome2.length()); + + // Don't use position 0 (because this just swaps the values) unless it's the only choice. + size_t minPoint = (minLength > 0? 1 : 0); + assert(minPoint <= minLength); + + size_t randomPoint = SimulationRNG::uniformInt(minPoint, minLength); + return buildChromosomesBySwappingParts(_chromosome1, _chromosome2, randomPoint); + }; +} + +function phaser::fixedPointCrossover(double _crossoverPoint) +{ + assert(0.0 <= _crossoverPoint && _crossoverPoint <= 1.0); + + return [=](Chromosome const& _chromosome1, Chromosome const& _chromosome2) + { + size_t minLength = min(_chromosome1.length(), _chromosome2.length()); + size_t concretePoint = static_cast(round(minLength * _crossoverPoint)); + + return buildChromosomesBySwappingParts(_chromosome1, _chromosome2, concretePoint); + }; +} diff --git a/tools/yulPhaser/Mutations.h b/tools/yulPhaser/Mutations.h index b18f195ef157..c934d71de324 100644 --- a/tools/yulPhaser/Mutations.h +++ b/tools/yulPhaser/Mutations.h @@ -23,11 +23,15 @@ #include #include +#include namespace solidity::phaser { +using ChromosomePair = std::tuple; + using Mutation = Chromosome(Chromosome const&); +using Crossover = ChromosomePair(Chromosome const&, Chromosome const&); // MUTATIONS @@ -53,4 +57,20 @@ std::function alternativeMutations( std::function _mutation2 ); +// CROSSOVER + +/// Creates a crossover operator that randomly selects a number between 0 and 1 and uses it as the +/// position at which to perform perform @a fixedPointCrossover. +std::function randomPointCrossover(); + +/// Creates a crossover operator that always chooses a point that lies at @a _crossoverPoint +/// percent of the length of the shorter chromosome. Then creates a pair of chromosomes by +/// splitting both inputs at the crossover point and stitching the resulting parts. The first +/// output is created from the first half or first input and the second half of the second input +/// The second output from the remaining two halves. +/// +/// Avoids selecting position 0 (since this just produces a chromosome identical to the second one) +/// unless there is no other choice (i.e. one of the chromosomes is empty). +std::function fixedPointCrossover(double _crossoverPoint); + } From 92b54d83a3388e80dd8a340aacda0e7e7858041e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 14 Feb 2020 19:49:45 +0100 Subject: [PATCH 007/165] [yul-phaser] Common: Add geneSubstitution() mutation --- test/yulPhaser/Common.cpp | 12 ++++++++++++ test/yulPhaser/Common.h | 5 +++++ test/yulPhaser/CommonTest.cpp | 11 +++++++++++ 3 files changed, 28 insertions(+) diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp index 52cde95900af..f9000921f614 100644 --- a/test/yulPhaser/Common.cpp +++ b/test/yulPhaser/Common.cpp @@ -31,6 +31,18 @@ function phaser::test::wholeChromosomeReplacement(Chromosome _newChrom return [_newChromosome = move(_newChromosome)](Chromosome const&) { return _newChromosome; }; } +function phaser::test::geneSubstitution(size_t _geneIndex, string _geneValue) +{ + return [=](Chromosome const& _chromosome) + { + vector newGenes = _chromosome.optimisationSteps(); + assert(_geneIndex < newGenes.size()); + newGenes[_geneIndex] = _geneValue; + + return Chromosome(newGenes); + }; +} + vector phaser::test::chromosomeLengths(Population const& _population) { vector lengths; diff --git a/test/yulPhaser/Common.h b/test/yulPhaser/Common.h index cbec90f7883a..a59c7eed123c 100644 --- a/test/yulPhaser/Common.h +++ b/test/yulPhaser/Common.h @@ -59,6 +59,11 @@ class ChromosomeLengthMetric: public FitnessMetric /// Mutation that always replaces the whole chromosome with the one specified in the parameter. std::function wholeChromosomeReplacement(Chromosome _newChromosome); +/// Mutation that always replaces the optimisation step at position @a _geneIndex with @a _geneValue. +/// +/// The chromosome must be long enough for this position to exist. +std::function geneSubstitution(size_t _geneIndex, std::string _geneValue); + // CHROMOSOME AND POPULATION HELPERS /// Returns a vector containing lengths of all chromosomes in the population (in the same order). diff --git a/test/yulPhaser/CommonTest.cpp b/test/yulPhaser/CommonTest.cpp index 3456a66404bf..efc511a80e62 100644 --- a/test/yulPhaser/CommonTest.cpp +++ b/test/yulPhaser/CommonTest.cpp @@ -46,6 +46,17 @@ BOOST_AUTO_TEST_CASE(wholeChromosomeReplacement_should_replace_whole_chromosome_ BOOST_TEST(mutation(Chromosome("ccc")) == Chromosome("aaa")); } +BOOST_AUTO_TEST_CASE(geneSubstitution_should_change_a_single_gene_at_a_given_index) +{ + Chromosome chromosome("aaccff"); + + function mutation1 = geneSubstitution(0, chromosome.optimisationSteps()[5]); + BOOST_TEST(mutation1(chromosome) == Chromosome("faccff")); + + function mutation2 = geneSubstitution(5, chromosome.optimisationSteps()[0]); + BOOST_TEST(mutation2(chromosome) == Chromosome("aaccfa")); +} + BOOST_AUTO_TEST_CASE(chromosomeLengths_should_return_lengths_of_all_chromosomes_in_a_population) { shared_ptr fitnessMetric = make_shared(); From 7e80ac861f4968bdb3ac9bc5997fd258d78bcc20 Mon Sep 17 00:00:00 2001 From: cameel Date: Wed, 5 Feb 2020 16:55:50 +0100 Subject: [PATCH 008/165] [yul-phaser] Population: Add mutate() and crossover() methods --- test/CMakeLists.txt | 1 + test/yulPhaser/Population.cpp | 66 ++++++++++++++++++++++++++++++++++ tools/yulPhaser/Population.cpp | 26 ++++++++++++++ tools/yulPhaser/Population.h | 4 +++ 4 files changed, 97 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb4b8241c1fd..da6995e384e2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -158,6 +158,7 @@ set(yul_phaser_sources ../tools/yulPhaser/Chromosome.cpp ../tools/yulPhaser/FitnessMetrics.cpp ../tools/yulPhaser/GeneticAlgorithms.cpp + ../tools/yulPhaser/Mutations.cpp ../tools/yulPhaser/PairSelections.cpp ../tools/yulPhaser/Population.cpp ../tools/yulPhaser/Program.cpp diff --git a/test/yulPhaser/Population.cpp b/test/yulPhaser/Population.cpp index 98532c9dceee..3e228f6279ba 100644 --- a/test/yulPhaser/Population.cpp +++ b/test/yulPhaser/Population.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include +#include #include #include #include @@ -226,6 +228,70 @@ BOOST_FIXTURE_TEST_CASE(select_should_return_empty_population_if_selection_is_em BOOST_TEST(population.select(selection).individuals().empty()); } +BOOST_FIXTURE_TEST_CASE(mutate_should_return_population_containing_individuals_indicated_by_selection_with_mutation_applied, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")}); + RangeSelection selection(0.25, 0.75); + assert(selection.materialise(population.individuals().size()) == (vector{1, 2})); + + Population expectedPopulation(m_fitnessMetric, {Chromosome("fc"), Chromosome("fg")}); + + BOOST_TEST(population.mutate(selection, geneSubstitution(0, BlockFlattener::name)) == expectedPopulation); +} + +BOOST_FIXTURE_TEST_CASE(mutate_should_include_duplicates_if_selection_contains_duplicates, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa")}); + RangeSelection selection(0.0, 1.0); + assert(selection.materialise(population.individuals().size()) == (vector{0, 1})); + + BOOST_TEST( + population.mutate(selection, geneSubstitution(0, BlockFlattener::name)) == + Population(m_fitnessMetric, {Chromosome("fa"), Chromosome("fa")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(mutate_should_return_empty_population_if_selection_is_empty, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc")}); + RangeSelection selection(0.0, 0.0); + assert(selection.materialise(population.individuals().size()).empty()); + + BOOST_TEST(population.mutate(selection, geneSubstitution(0, BlockFlattener::name)).individuals().empty()); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_return_population_containing_individuals_indicated_by_selection_with_crossover_applied, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")}); + PairMosaicSelection selection({{0, 1}, {2, 1}}, 0.5); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 1}, {2, 1}})); + + Population expectedPopulation(m_fitnessMetric, {Chromosome("ac"), Chromosome("ca"), Chromosome("cg"), Chromosome("gc")}); + + BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)) == expectedPopulation); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_include_duplicates_if_selection_contains_duplicates, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa")}); + PairMosaicSelection selection({{0, 0}, {1, 1}}, 1.0); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 0}, {1, 1}})); + + BOOST_TEST( + population.crossover(selection, fixedPointCrossover(0.5)) == + Population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa"), Chromosome("aa"), Chromosome("aa")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(crossover_should_return_empty_population_if_selection_is_empty, PopulationFixture) +{ + Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc")}); + PairMosaicSelection selection({}, 0.0); + assert(selection.materialise(population.individuals().size()).empty()); + + BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)).individuals().empty()); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index b39f5dad5d9a..61702634fbcd 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -17,6 +17,7 @@ #include +#include #include #include @@ -93,6 +94,31 @@ Population Population::select(Selection const& _selection) const return Population(m_fitnessMetric, selectedIndividuals); } +Population Population::mutate(Selection const& _selection, function _mutation) const +{ + vector mutatedIndividuals; + for (size_t i: _selection.materialise(m_individuals.size())) + mutatedIndividuals.emplace_back(_mutation(m_individuals[i].chromosome), *m_fitnessMetric); + + return Population(m_fitnessMetric, mutatedIndividuals); +} + +Population Population::crossover(PairSelection const& _selection, function _crossover) const +{ + vector crossedIndividuals; + for (auto const& [i, j]: _selection.materialise(m_individuals.size())) + { + auto [childChromosome1, childChromosome2] = _crossover( + m_individuals[i].chromosome, + m_individuals[j].chromosome + ); + crossedIndividuals.emplace_back(move(childChromosome1), *m_fitnessMetric); + crossedIndividuals.emplace_back(move(childChromosome2), *m_fitnessMetric); + } + + return Population(m_fitnessMetric, crossedIndividuals); +} + Population operator+(Population _a, Population _b) { // This operator is meant to be used only with populations sharing the same metric (and, to make diff --git a/tools/yulPhaser/Population.h b/tools/yulPhaser/Population.h index f4f42346de22..29c82efedc17 100644 --- a/tools/yulPhaser/Population.h +++ b/tools/yulPhaser/Population.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ solidity::phaser::Population operator+(solidity::phaser::Population _a, solidity namespace solidity::phaser { +class PairSelection; class Selection; /** @@ -104,6 +106,8 @@ class Population ); Population select(Selection const& _selection) const; + Population mutate(Selection const& _selection, std::function _mutation) const; + Population crossover(PairSelection const& _selection, std::function _crossover) const; friend Population (::operator+)(Population _a, Population _b); std::shared_ptr fitnessMetric() const { return m_fitnessMetric; } From fc4fedb2142028a5169e93e30e1a644866e1893b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 6 Feb 2020 00:51:11 +0100 Subject: [PATCH 009/165] [yul-phaser] Add GenerationalElitistWithExclusivePools algorithm --- test/yulPhaser/GeneticAlgorithms.cpp | 102 ++++++++++++++++++++++++++ tools/yulPhaser/GeneticAlgorithms.cpp | 27 +++++++ tools/yulPhaser/GeneticAlgorithms.h | 53 +++++++++++++ 3 files changed, 182 insertions(+) diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index aaa0a0b05d34..0d32e9c1d369 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -29,6 +29,7 @@ #include #include +#include #include using namespace std; @@ -132,6 +133,107 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_any_chromosomes_if_whole BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); } +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(GenerationalElitistWithExclusivePoolsTest) + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_regenerate_rest_of_population, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.2, + /* crossoverPoolSize = */ 0.2, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 1.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(population, m_output, options); + assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + + algorithm.runNextRound(); + + BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{0, 0, 3, 3, 3, 3, 3, 3, 3, 3})); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individuals, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.2, + /* crossoverPoolSize = */ 0.2, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 0.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(population, m_output, options); + assert(chromosomeLengths(algorithm.population()) == (vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + + algorithm.runNextRound(); + + BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 3, 3, 3, 3, 7, 7})); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossover_pool_by_mutating_the_elite, GeneticAlgorithmFixture) +{ + auto population = Population::makeRandom(m_fitnessMetric, 20, 5, 5); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.8, + /* crossoverPoolSize = */ 0.0, + /* randomisationChance = */ 0.5, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 1.0, + /* percentGenesToAddOrDelete = */ 1.0, + }; + GenerationalElitistWithExclusivePools algorithm(population, m_output, options); + + SimulationRNG::reset(1); + algorithm.runNextRound(); + + BOOST_TEST(( + chromosomeLengths(algorithm.population()) == + vector{0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 11, 11, 11} + )); +} + +BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossover_pool_by_crossing_over_the_elite, GeneticAlgorithmFixture) +{ + auto population = ( + Population(m_fitnessMetric, {Chromosome("aa"), Chromosome("ff")}) + + Population::makeRandom(m_fitnessMetric, 8, 6, 6) + ); + + GenerationalElitistWithExclusivePools::Options options = { + /* mutationPoolSize = */ 0.0, + /* crossoverPoolSize = */ 0.8, + /* randomisationChance = */ 0.0, + /* deletionVsAdditionChance = */ 0.0, + /* percentGenesToRandomise = */ 0.0, + /* percentGenesToAddOrDelete = */ 0.0, + }; + GenerationalElitistWithExclusivePools algorithm(population, m_output, options); + assert((chromosomeLengths(algorithm.population()) == vector{2, 2, 6, 6, 6, 6, 6, 6, 6, 6})); + + SimulationRNG::reset(1); + algorithm.runNextRound(); + + vector const& newIndividuals = algorithm.population().individuals(); + BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{2, 2, 2, 2, 2, 2, 2, 2, 2, 2})); + for (auto& individual: newIndividuals) + BOOST_TEST(( + individual.chromosome == Chromosome("aa") || + individual.chromosome == Chromosome("af") || + individual.chromosome == Chromosome("fa") || + individual.chromosome == Chromosome("ff") + )); + BOOST_TEST(any_of(newIndividuals.begin() + 2, newIndividuals.end(), [](auto& individual){ + return individual.chromosome != Chromosome("aa") && individual.chromosome != Chromosome("ff"); + })); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp index 756a410f7663..ae32960b4e51 100644 --- a/tools/yulPhaser/GeneticAlgorithms.cpp +++ b/tools/yulPhaser/GeneticAlgorithms.cpp @@ -16,7 +16,9 @@ */ #include +#include #include +#include using namespace std; using namespace solidity::phaser; @@ -48,3 +50,28 @@ void RandomAlgorithm::runNextRound() m_options.maxChromosomeLength ); } + +void GenerationalElitistWithExclusivePools::runNextRound() +{ + double elitePoolSize = 1.0 - (m_options.mutationPoolSize + m_options.crossoverPoolSize); + RangeSelection elite(0.0, elitePoolSize); + + m_population = + m_population.select(elite) + + m_population.select(elite).mutate( + RandomSelection(m_options.mutationPoolSize / elitePoolSize), + alternativeMutations( + m_options.randomisationChance, + geneRandomisation(m_options.percentGenesToRandomise), + alternativeMutations( + m_options.deletionVsAdditionChance, + geneDeletion(m_options.percentGenesToAddOrDelete), + geneAddition(m_options.percentGenesToAddOrDelete) + ) + ) + ) + + m_population.select(elite).crossover( + RandomPairSelection(m_options.crossoverPoolSize / elitePoolSize / 2), + randomPointCrossover() + ); +} diff --git a/tools/yulPhaser/GeneticAlgorithms.h b/tools/yulPhaser/GeneticAlgorithms.h index a7600d8942c0..bab475c4edcd 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -112,4 +112,57 @@ class RandomAlgorithm: public GeneticAlgorithm Options m_options; }; +/** + * A generational, elitist genetic algorithm that replaces the population by mutating and crossing + * over chromosomes from the elite. + * + * The elite consists of individuals not included in the crossover and mutation pools. + * The crossover operator used is @a randomPointCrossover. The mutation operator is randomly chosen + * from three possibilities: @a geneRandomisation, @a geneDeletion or @a geneAddition (with + * configurable probabilities). Each mutation also has a parameter determining the chance of a gene + * being affected by it. + */ +class GenerationalElitistWithExclusivePools: public GeneticAlgorithm +{ +public: + struct Options + { + double mutationPoolSize; ///< Percentage of population to regenerate using mutations in each round. + double crossoverPoolSize; ///< Percentage of population to regenerate using crossover in each round. + double randomisationChance; ///< The chance of choosing @a geneRandomisation as the mutation to perform + double deletionVsAdditionChance; ///< The chance of choosing @a geneDeletion as the mutation if randomisation was not chosen. + double percentGenesToRandomise; ///< The chance of any given gene being mutated in gene randomisation. + double percentGenesToAddOrDelete; ///< The chance of a gene being added (or deleted) in gene addition (or deletion). + + bool isValid() const + { + return ( + 0 <= mutationPoolSize && mutationPoolSize <= 1.0 && + 0 <= crossoverPoolSize && crossoverPoolSize <= 1.0 && + 0 <= randomisationChance && randomisationChance <= 1.0 && + 0 <= deletionVsAdditionChance && deletionVsAdditionChance <= 1.0 && + 0 <= percentGenesToRandomise && percentGenesToRandomise <= 1.0 && + 0 <= percentGenesToAddOrDelete && percentGenesToAddOrDelete <= 1.0 && + mutationPoolSize + crossoverPoolSize <= 1.0 + ); + } + }; + + GenerationalElitistWithExclusivePools( + Population _initialPopulation, + std::ostream& _outputStream, + Options const& _options + ): + GeneticAlgorithm(_initialPopulation, _outputStream), + m_options(_options) + { + assert(_options.isValid()); + } + + void runNextRound() override; + +private: + Options m_options; +}; + } From 0c61f6d18f72de39c74304ca6152ce920db7edeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 6 Feb 2020 05:29:19 +0100 Subject: [PATCH 010/165] [yul-phaser] main: Command-line option for algorithm selection --- tools/yulPhaser/main.cpp | 63 ++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index e3464029c4f0..f1a0cd00154f 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -39,6 +39,34 @@ using namespace solidity::util; namespace po = boost::program_options; +enum class Algorithm +{ + Random +}; + +istream& operator>>(istream& inputStream, Algorithm& algorithm) +{ + string value; + inputStream >> value; + + if (value == "random") + algorithm = Algorithm::Random; + else + inputStream.setstate(ios_base::failbit); + + return inputStream; +} + +ostream& operator<<(ostream& outputStream, Algorithm algorithm) +{ + if (algorithm == Algorithm::Random) + outputStream << "random"; + else + outputStream.setstate(ios_base::failbit); + + return outputStream; +} + namespace { @@ -69,7 +97,7 @@ CharStream loadSource(string const& _sourcePath) return CharStream(sourceCode, _sourcePath); } -void runAlgorithm(string const& _sourcePath) +void runAlgorithm(string const& _sourcePath, Algorithm _algorithm) { constexpr size_t populationSize = 20; constexpr size_t minChromosomeLength = 12; @@ -83,15 +111,24 @@ void runAlgorithm(string const& _sourcePath) minChromosomeLength, maxChromosomeLength ); - RandomAlgorithm( - population, - cout, + + switch (_algorithm) + { + case Algorithm::Random: { - /* elitePoolSize = */ 1.0 / populationSize, - /* minChromosomeLength = */ minChromosomeLength, - /* maxChromosomeLength = */ maxChromosomeLength, + RandomAlgorithm( + population, + cout, + { + /* elitePoolSize = */ 1.0 / populationSize, + /* minChromosomeLength = */ minChromosomeLength, + /* maxChromosomeLength = */ maxChromosomeLength, + } + ).run(); + + break; } - ).run(); + } } CommandLineParsingResult parseCommandLine(int argc, char** argv) @@ -114,6 +151,11 @@ CommandLineParsingResult parseCommandLine(int argc, char** argv) ("help", "Show help message and exit.") ("input-file", po::value()->required(), "Input file") ("seed", po::value(), "Seed for the random number generator") + ( + "algorithm", + po::value()->default_value(Algorithm::Random), + "Algorithm" + ) ; po::positional_options_description positionalDescription; @@ -160,7 +202,10 @@ int main(int argc, char** argv) try { - runAlgorithm(parsingResult.arguments["input-file"].as()); + runAlgorithm( + parsingResult.arguments["input-file"].as(), + parsingResult.arguments["algorithm"].as() + ); } catch (InvalidProgram const& _exception) { From a3e97108c5e0a98c685d0696a84f944d463f4776 Mon Sep 17 00:00:00 2001 From: cameel Date: Wed, 5 Feb 2020 17:01:38 +0100 Subject: [PATCH 011/165] [yul-phaser] main: Add GenerationalElitistWithExclusivePools as an option and make it the default --- tools/yulPhaser/main.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index f1a0cd00154f..99402d56b27d 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -41,7 +41,8 @@ namespace po = boost::program_options; enum class Algorithm { - Random + Random, + GEWEP }; istream& operator>>(istream& inputStream, Algorithm& algorithm) @@ -51,6 +52,8 @@ istream& operator>>(istream& inputStream, Algorithm& algorithm) if (value == "random") algorithm = Algorithm::Random; + else if (value == "GEWEP") + algorithm = Algorithm::GEWEP; else inputStream.setstate(ios_base::failbit); @@ -61,6 +64,8 @@ ostream& operator<<(ostream& outputStream, Algorithm algorithm) { if (algorithm == Algorithm::Random) outputStream << "random"; + else if (algorithm == Algorithm::GEWEP) + outputStream << "GEWEP"; else outputStream.setstate(ios_base::failbit); @@ -126,6 +131,23 @@ void runAlgorithm(string const& _sourcePath, Algorithm _algorithm) } ).run(); + break; + } + case Algorithm::GEWEP: + { + GenerationalElitistWithExclusivePools( + population, + cout, + { + /* mutationPoolSize = */ 0.25, + /* crossoverPoolSize = */ 0.25, + /* randomisationChance = */ 0.9, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 0.1, + /* percentGenesToAddOrDelete = */ 0.1, + } + ).run(); + break; } } @@ -153,7 +175,7 @@ CommandLineParsingResult parseCommandLine(int argc, char** argv) ("seed", po::value(), "Seed for the random number generator") ( "algorithm", - po::value()->default_value(Algorithm::Random), + po::value()->default_value(Algorithm::GEWEP), "Algorithm" ) ; From 763bdb1d51e4e212c5ccfa4bf23d2e37e4e41529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Feb 2020 23:44:06 +0100 Subject: [PATCH 012/165] [yul-phaser] Change the design of crossover operators so that they produce a single chromosome rather than a pair --- test/yulPhaser/Mutations.cpp | 97 ++++++++++++++++----------- test/yulPhaser/Population.cpp | 10 +-- tools/yulPhaser/GeneticAlgorithms.cpp | 2 +- tools/yulPhaser/Mutations.cpp | 14 ++-- tools/yulPhaser/Mutations.h | 11 ++- tools/yulPhaser/Population.cpp | 5 +- 6 files changed, 74 insertions(+), 65 deletions(-) diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index 49f6e7f0224d..66852ed55089 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -214,11 +214,14 @@ BOOST_AUTO_TEST_CASE(alternativeMutations_should_always_choose_second_mutation_i BOOST_AUTO_TEST_CASE(randomPointCrossover_should_swap_chromosome_parts_at_random_point) { - SimulationRNG::reset(1); function crossover = randomPointCrossover(); - auto [result1, result2] = crossover(Chromosome("aaaaaaaaaa"), Chromosome("cccccc")); + SimulationRNG::reset(1); + Chromosome result1 = crossover(Chromosome("aaaaaaaaaa"), Chromosome("cccccc")); BOOST_TEST(result1 == Chromosome("aaaccc")); + + SimulationRNG::reset(1); + Chromosome result2 = crossover(Chromosome("cccccc"), Chromosome("aaaaaaaaaa")); BOOST_TEST(result2 == Chromosome("cccaaaaaaa")); } @@ -229,12 +232,19 @@ BOOST_AUTO_TEST_CASE(randomPointCrossover_should_only_consider_points_available_ for (size_t i = 0; i < 30; ++i) { - auto [result1, result2] = crossover(Chromosome("aaa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result1 = crossover(Chromosome("aaa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result2 = crossover(Chromosome("TTTTTTTTTTTTTTTTTTTT"), Chromosome("aaa")); + BOOST_TEST(( + result1 == Chromosome("TTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") + )); BOOST_TEST(( - (result1 == Chromosome("TTTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("aaa")) || - (result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("Taa")) || - (result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTa")) || - (result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTT")) + result2 == Chromosome("aaa") || + result2 == Chromosome("Taa") || + result2 == Chromosome("TTa") || + result2 == Chromosome("TTT") )); } } @@ -246,7 +256,8 @@ BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if for (size_t i = 0; i < 30; ++i) { - auto [result1, result2] = crossover(Chromosome("aa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result1 = crossover(Chromosome("aa"), Chromosome("TTTTTTTTTTTTTTTTTTTT")); + Chromosome result2 = crossover(Chromosome("TTTTTTTTTTTTTTTTTTTT"), Chromosome("aa")); BOOST_TEST(result1 != Chromosome("TTTTTTTTTTTTTTTTTTTT")); BOOST_TEST(result2 != Chromosome("aa")); } @@ -259,7 +270,8 @@ BOOST_AUTO_TEST_CASE(randomPointCrossover_should_never_split_at_position_zero_if for (size_t i = 0; i < 30; ++i) { - auto [result1, result2] = crossover(Chromosome("a"), Chromosome("T")); + Chromosome result1 = crossover(Chromosome("a"), Chromosome("T")); + Chromosome result2 = crossover(Chromosome("T"), Chromosome("a")); BOOST_TEST(result1 == Chromosome("a")); BOOST_TEST(result2 == Chromosome("T")); } @@ -270,8 +282,8 @@ BOOST_AUTO_TEST_CASE(randomPointCrossover_should_work_even_if_one_chromosome_is_ function crossover = randomPointCrossover(); SimulationRNG::reset(1); - BOOST_CHECK(crossover(Chromosome("ff"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("af"))); - BOOST_CHECK(crossover(Chromosome("a"), Chromosome("ff")) == ChromosomePair(Chromosome("af"), Chromosome("f"))); + BOOST_CHECK(crossover(Chromosome("ff"), Chromosome("a")) == Chromosome("f")); + BOOST_CHECK(crossover(Chromosome("a"), Chromosome("ff")) == Chromosome("af")); } BOOST_AUTO_TEST_CASE(randomPointCrossover_should_split_at_position_zero_only_if_at_least_one_chromosome_is_empty) @@ -282,52 +294,59 @@ BOOST_AUTO_TEST_CASE(randomPointCrossover_should_split_at_position_zero_only_if_ function crossover = randomPointCrossover(); SimulationRNG::reset(1); - BOOST_CHECK(crossover(empty, empty) == ChromosomePair(empty, empty)); - BOOST_CHECK(crossover(unsplittable, empty) == ChromosomePair(empty, unsplittable)); - BOOST_CHECK(crossover(empty, unsplittable) == ChromosomePair(unsplittable, empty)); - BOOST_CHECK(crossover(splittable, empty) == ChromosomePair(empty, splittable)); - BOOST_CHECK(crossover(empty, splittable) == ChromosomePair(splittable, empty)); + BOOST_CHECK(crossover(empty, empty) == empty); + BOOST_CHECK(crossover(unsplittable, empty) == empty); + BOOST_CHECK(crossover(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover(splittable, empty) == empty); + BOOST_CHECK(crossover(empty, splittable) == splittable); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_swap_chromosome_parts_at_given_point) { - auto [result1, result2] = fixedPointCrossover(0.8)(Chromosome("aaaaaaaaaa"), Chromosome("cccccccccc")); + Chromosome result1 = fixedPointCrossover(0.8)(Chromosome("aaaaaaaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.8)(Chromosome("cccccccccc"), Chromosome("aaaaaaaaaa")); BOOST_TEST(result1 == Chromosome("aaaaaaaacc")); BOOST_TEST(result2 == Chromosome("ccccccccaa")); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_determine_crossover_point_based_on_length_of_shorter_chromosome) { - auto [result1, result2] = fixedPointCrossover(0.4)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result1 = fixedPointCrossover(0.4)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.4)(Chromosome("cccccccccc"), Chromosome("aaaaa")); BOOST_TEST(result1 == Chromosome("aacccccccc")); BOOST_TEST(result2 == Chromosome("ccaaa")); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_round_split_point) { - auto [result1, result2] = fixedPointCrossover(0.49)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result1 = fixedPointCrossover(0.49)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result2 = fixedPointCrossover(0.49)(Chromosome("ccccc"), Chromosome("aaaaa")); BOOST_TEST(result1 == Chromosome("aaccc")); BOOST_TEST(result2 == Chromosome("ccaaa")); - auto [result3, result4] = fixedPointCrossover(0.50)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result3 = fixedPointCrossover(0.50)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result4 = fixedPointCrossover(0.50)(Chromosome("ccccc"), Chromosome("aaaaa")); BOOST_TEST(result3 == Chromosome("aaacc")); BOOST_TEST(result4 == Chromosome("cccaa")); - auto [result5, result6] = fixedPointCrossover(0.51)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result5 = fixedPointCrossover(0.51)(Chromosome("aaaaa"), Chromosome("ccccc")); + Chromosome result6 = fixedPointCrossover(0.51)(Chromosome("ccccc"), Chromosome("aaaaa")); BOOST_TEST(result5 == Chromosome("aaacc")); BOOST_TEST(result6 == Chromosome("cccaa")); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_position_zero_if_explicitly_requested) { - auto [result1, result2] = fixedPointCrossover(0.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result1 = fixedPointCrossover(0.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(0.0)(Chromosome("cccccccccc"), Chromosome("aaaaa")); BOOST_TEST(result1 == Chromosome("cccccccccc")); BOOST_TEST(result2 == Chromosome("aaaaa")); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_end_of_shorter_chromosome_if_crossover_point_is_after_last_position) { - auto [result1, result2] = fixedPointCrossover(1.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result1 = fixedPointCrossover(1.0)(Chromosome("aaaaa"), Chromosome("cccccccccc")); + Chromosome result2 = fixedPointCrossover(1.0)(Chromosome("cccccccccc"), Chromosome("aaaaa")); BOOST_TEST(result1 == Chromosome("aaaaaccccc")); BOOST_TEST(result2 == Chromosome("ccccc")); } @@ -335,16 +354,16 @@ BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_split_at_end_of_shorter_chromoso BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_select_correct_split_point_for_unsplittable_chromosomes) { function crossover00 = fixedPointCrossover(0.0); - BOOST_CHECK(crossover00(Chromosome("fff"), Chromosome("a")) == ChromosomePair(Chromosome("a"), Chromosome("fff"))); - BOOST_CHECK(crossover00(Chromosome("a"), Chromosome("fff")) == ChromosomePair(Chromosome("fff"), Chromosome("a"))); + BOOST_CHECK(crossover00(Chromosome("fff"), Chromosome("a")) == Chromosome("a")); + BOOST_CHECK(crossover00(Chromosome("a"), Chromosome("fff")) == Chromosome("fff")); - BOOST_CHECK(crossover00(Chromosome("f"), Chromosome("a")) == ChromosomePair(Chromosome("a"), Chromosome("f"))); + BOOST_CHECK(crossover00(Chromosome("f"), Chromosome("a")) == Chromosome("a")); function crossover10 = fixedPointCrossover(1.0); - BOOST_CHECK(crossover10(Chromosome("fff"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("aff"))); - BOOST_CHECK(crossover10(Chromosome("a"), Chromosome("fff")) == ChromosomePair(Chromosome("aff"), Chromosome("f"))); + BOOST_CHECK(crossover10(Chromosome("fff"), Chromosome("a")) == Chromosome("f")); + BOOST_CHECK(crossover10(Chromosome("a"), Chromosome("fff")) == Chromosome("aff")); - BOOST_CHECK(crossover10(Chromosome("f"), Chromosome("a")) == ChromosomePair(Chromosome("f"), Chromosome("a"))); + BOOST_CHECK(crossover10(Chromosome("f"), Chromosome("a")) == Chromosome("f")); } BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_always_use_position_zero_as_split_point_when_chromosome_empty) @@ -354,18 +373,18 @@ BOOST_AUTO_TEST_CASE(fixedPointCrossover_should_always_use_position_zero_as_spli Chromosome splittable("aaaa"); function crossover00 = fixedPointCrossover(0.0); - BOOST_CHECK(crossover00(empty, empty) == ChromosomePair(empty, empty)); - BOOST_CHECK(crossover00(unsplittable, empty) == ChromosomePair(empty, unsplittable)); - BOOST_CHECK(crossover00(empty, unsplittable) == ChromosomePair(unsplittable, empty)); - BOOST_CHECK(crossover00(splittable, empty) == ChromosomePair(empty, splittable)); - BOOST_CHECK(crossover00(empty, splittable) == ChromosomePair(splittable, empty)); + BOOST_CHECK(crossover00(empty, empty) == empty); + BOOST_CHECK(crossover00(unsplittable, empty) == empty); + BOOST_CHECK(crossover00(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover00(splittable, empty) == empty); + BOOST_CHECK(crossover00(empty, splittable) == splittable); function crossover10 = fixedPointCrossover(1.0); - BOOST_CHECK(crossover10(empty, empty) == ChromosomePair(empty, empty)); - BOOST_CHECK(crossover10(unsplittable, empty) == ChromosomePair(empty, unsplittable)); - BOOST_CHECK(crossover10(empty, unsplittable) == ChromosomePair(unsplittable, empty)); - BOOST_CHECK(crossover10(splittable, empty) == ChromosomePair(empty, splittable)); - BOOST_CHECK(crossover10(empty, splittable) == ChromosomePair(splittable, empty)); + BOOST_CHECK(crossover10(empty, empty) == empty); + BOOST_CHECK(crossover10(unsplittable, empty) == empty); + BOOST_CHECK(crossover10(empty, unsplittable) == unsplittable); + BOOST_CHECK(crossover10(splittable, empty) == empty); + BOOST_CHECK(crossover10(empty, splittable) == splittable); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/yulPhaser/Population.cpp b/test/yulPhaser/Population.cpp index 3e228f6279ba..2363256e44ae 100644 --- a/test/yulPhaser/Population.cpp +++ b/test/yulPhaser/Population.cpp @@ -263,10 +263,10 @@ BOOST_FIXTURE_TEST_CASE(mutate_should_return_empty_population_if_selection_is_em BOOST_FIXTURE_TEST_CASE(crossover_should_return_population_containing_individuals_indicated_by_selection_with_crossover_applied, PopulationFixture) { Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("cc"), Chromosome("gg"), Chromosome("hh")}); - PairMosaicSelection selection({{0, 1}, {2, 1}}, 0.5); - assert(selection.materialise(population.individuals().size()) == (vector>{{0, 1}, {2, 1}})); + PairMosaicSelection selection({{0, 1}, {2, 1}}, 1.0); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 1}, {2, 1}, {0, 1}, {2, 1}})); - Population expectedPopulation(m_fitnessMetric, {Chromosome("ac"), Chromosome("ca"), Chromosome("cg"), Chromosome("gc")}); + Population expectedPopulation(m_fitnessMetric, {Chromosome("ac"), Chromosome("ac"), Chromosome("gc"), Chromosome("gc")}); BOOST_TEST(population.crossover(selection, fixedPointCrossover(0.5)) == expectedPopulation); } @@ -274,8 +274,8 @@ BOOST_FIXTURE_TEST_CASE(crossover_should_return_population_containing_individual BOOST_FIXTURE_TEST_CASE(crossover_should_include_duplicates_if_selection_contains_duplicates, PopulationFixture) { Population population(m_fitnessMetric, {Chromosome("aa"), Chromosome("aa")}); - PairMosaicSelection selection({{0, 0}, {1, 1}}, 1.0); - assert(selection.materialise(population.individuals().size()) == (vector>{{0, 0}, {1, 1}})); + PairMosaicSelection selection({{0, 0}, {1, 1}}, 2.0); + assert(selection.materialise(population.individuals().size()) == (vector>{{0, 0}, {1, 1}, {0, 0}, {1, 1}})); BOOST_TEST( population.crossover(selection, fixedPointCrossover(0.5)) == diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp index ae32960b4e51..fa37ac5e36ee 100644 --- a/tools/yulPhaser/GeneticAlgorithms.cpp +++ b/tools/yulPhaser/GeneticAlgorithms.cpp @@ -71,7 +71,7 @@ void GenerationalElitistWithExclusivePools::runNextRound() ) ) + m_population.select(elite).crossover( - RandomPairSelection(m_options.crossoverPoolSize / elitePoolSize / 2), + RandomPairSelection(m_options.crossoverPoolSize / elitePoolSize), randomPointCrossover() ); } diff --git a/tools/yulPhaser/Mutations.cpp b/tools/yulPhaser/Mutations.cpp index f639d8f6afb1..86f815198d07 100644 --- a/tools/yulPhaser/Mutations.cpp +++ b/tools/yulPhaser/Mutations.cpp @@ -98,7 +98,7 @@ function phaser::alternativeMutations( namespace { -ChromosomePair buildChromosomesBySwappingParts( +Chromosome buildChromosomesBySwappingParts( Chromosome const& _chromosome1, Chromosome const& _chromosome2, size_t _crossoverPoint @@ -110,15 +110,9 @@ ChromosomePair buildChromosomesBySwappingParts( auto begin1 = _chromosome1.optimisationSteps().begin(); auto begin2 = _chromosome2.optimisationSteps().begin(); - return ChromosomePair( - Chromosome( - vector(begin1, begin1 + _crossoverPoint) + - vector(begin2 + _crossoverPoint, _chromosome2.optimisationSteps().end()) - ), - Chromosome( - vector(begin2, begin2 + _crossoverPoint) + - vector(begin1 + _crossoverPoint, _chromosome1.optimisationSteps().end()) - ) + return Chromosome( + vector(begin1, begin1 + _crossoverPoint) + + vector(begin2 + _crossoverPoint, _chromosome2.optimisationSteps().end()) ); } diff --git a/tools/yulPhaser/Mutations.h b/tools/yulPhaser/Mutations.h index c934d71de324..bff48c52b204 100644 --- a/tools/yulPhaser/Mutations.h +++ b/tools/yulPhaser/Mutations.h @@ -28,10 +28,8 @@ namespace solidity::phaser { -using ChromosomePair = std::tuple; - using Mutation = Chromosome(Chromosome const&); -using Crossover = ChromosomePair(Chromosome const&, Chromosome const&); +using Crossover = Chromosome(Chromosome const&, Chromosome const&); // MUTATIONS @@ -64,10 +62,9 @@ std::function alternativeMutations( std::function randomPointCrossover(); /// Creates a crossover operator that always chooses a point that lies at @a _crossoverPoint -/// percent of the length of the shorter chromosome. Then creates a pair of chromosomes by -/// splitting both inputs at the crossover point and stitching the resulting parts. The first -/// output is created from the first half or first input and the second half of the second input -/// The second output from the remaining two halves. +/// percent of the length of the shorter chromosome. Then creates a new chromosome by +/// splitting both inputs at the crossover point and stitching output from the first half or first +/// input and the second half of the second input. /// /// Avoids selecting position 0 (since this just produces a chromosome identical to the second one) /// unless there is no other choice (i.e. one of the chromosomes is empty). diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index 61702634fbcd..ec63eb3bbe52 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -108,12 +108,11 @@ Population Population::crossover(PairSelection const& _selection, function crossedIndividuals; for (auto const& [i, j]: _selection.materialise(m_individuals.size())) { - auto [childChromosome1, childChromosome2] = _crossover( + auto childChromosome = _crossover( m_individuals[i].chromosome, m_individuals[j].chromosome ); - crossedIndividuals.emplace_back(move(childChromosome1), *m_fitnessMetric); - crossedIndividuals.emplace_back(move(childChromosome2), *m_fitnessMetric); + crossedIndividuals.emplace_back(move(childChromosome), *m_fitnessMetric); } return Population(m_fitnessMetric, crossedIndividuals); From 0fa2aa62b2f4333d48859627401256757c54da52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 15 Feb 2020 03:43:45 +0100 Subject: [PATCH 013/165] [yul-phaser] main: Lower gene mutation chance in GEWEP --- tools/yulPhaser/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 99402d56b27d..4af735d0bb12 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -143,8 +143,8 @@ void runAlgorithm(string const& _sourcePath, Algorithm _algorithm) /* crossoverPoolSize = */ 0.25, /* randomisationChance = */ 0.9, /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 0.1, - /* percentGenesToAddOrDelete = */ 0.1, + /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, + /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, } ).run(); From 1b1781580802c48837a80e1e07eed2ecaed9bfea Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 10 Mar 2020 13:21:25 +0100 Subject: [PATCH 014/165] SMTChecker docs test may issue a warning --- docs/security-considerations.rst | 2 ++ test/cmdlineTests.sh | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index ebf54b3a4592..829aab9e4f40 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -547,6 +547,7 @@ not mean loss of proving power. pragma solidity >=0.5.0; pragma experimental SMTChecker; + // This may report a warning if no SMT solver available. contract Recover { @@ -601,6 +602,7 @@ types. pragma solidity >=0.5.0; pragma experimental SMTChecker; // This will report a warning + contract Aliasing { uint[] array; diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 393f3da8bafc..ece4e581c3d7 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -77,6 +77,11 @@ function compileFull() expect_output=1 shift; fi + if [[ $1 = '-o' ]] + then + expect_output=2 + shift; + fi local files="$*" local output @@ -93,7 +98,7 @@ function compileFull() if [[ \ "$exit_code" -ne "$expected_exit_code" || \ ( $expect_output -eq 0 && -n "$errors" ) || \ - ( $expect_output -ne 0 && -z "$errors" ) \ + ( $expect_output -eq 1 && -z "$errors" ) \ ]] then printError "Unexpected compilation result:" @@ -350,6 +355,10 @@ SOLTMPDIR=$(mktemp -d) then opts="$opts -w" fi + if grep "This may report a warning" "$f" >/dev/null + then + opts="$opts -o" + fi compileFull $opts "$SOLTMPDIR/$f" done ) From bcefda747ce0bba9fc54c0295c50681d439222f0 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 10 Mar 2020 13:41:10 +0100 Subject: [PATCH 015/165] Do not run smtCheckerTestsJSON if no solver available --- test/libsolidity/SMTCheckerJSONTest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index 82c2b446b168..fad5a127f7aa 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -17,14 +17,18 @@ #include #include + +#include #include #include #include + #include #include #include #include #include + #include #include #include @@ -50,6 +54,9 @@ SMTCheckerJSONTest::SMTCheckerJSONTest(string const& _filename, langutil::EVMVer !m_smtResponses.isObject() ) BOOST_THROW_EXCEPTION(runtime_error("Invalid JSON file.")); + + if (ModelChecker::availableSolvers().none()) + m_shouldRun = false; } TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) From f8344cb4df414dadb83363db2241ea43a2911a53 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 10 Mar 2020 21:08:03 +0100 Subject: [PATCH 016/165] Set version to 0.6.5 --- CMakeLists.txt | 2 +- Changelog.md | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4278770f1dee..4a674c99e4e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.6.4") +set(PROJECT_VERSION "0.6.5") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) include(TestBigEndian) diff --git a/Changelog.md b/Changelog.md index 19e89adf5ebf..15221bb7d581 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,15 @@ +### 0.6.5 (unreleased) + +Language Features: + + +Compiler Features: + + +Bugfixes: + + + ### 0.6.4 (2020-03-10) Language Features: From 694da61b3910fdb2fd12ab0474b8f2f7f601250d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 10 Mar 2020 21:13:21 +0100 Subject: [PATCH 017/165] Remove PR template and empty general template. --- .github/ISSUE_TEMPLATE/general.md | 21 --------------------- .github/PULL_REQUEST_TEMPLATE.md | 22 ---------------------- 2 files changed, 43 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/general.md b/.github/ISSUE_TEMPLATE/general.md index 410b42e00558..e69de29bb2d1 100644 --- a/.github/ISSUE_TEMPLATE/general.md +++ b/.github/ISSUE_TEMPLATE/general.md @@ -1,21 +0,0 @@ ---- -name: General Feedback -about: Any general feedback (neither feature request nor bug reports) ---- - - -## Description - - diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 9fdbf158eeab..000000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,22 +0,0 @@ - - -### Description - - - -### Checklist -- [ ] Code compiles correctly -- [ ] All tests are passing -- [ ] New tests have been created which fail without the change (if possible) -- [ ] README / documentation was extended, if necessary -- [ ] Changelog entry (if change is visible to the user) -- [ ] Used meaningful commit messages From 92d4bbb0174be1e8c7e7a89d1c3f6d223ada3d7c Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 25 Feb 2020 17:57:28 +0100 Subject: [PATCH 018/165] Salt should be bytes32. --- libsolidity/ast/Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 3f54fccc6b9a..454ca8f3cb6f 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2954,7 +2954,7 @@ vector> FunctionType::makeStackItems() const if (m_valueSet) slots.emplace_back("value", TypeProvider::uint256()); if (m_saltSet) - slots.emplace_back("salt", TypeProvider::uint256()); + slots.emplace_back("salt", TypeProvider::fixedBytes(32)); if (bound()) for (auto const& [boundName, boundType]: m_parameterTypes.front()->stackItems()) slots.emplace_back("self_" + boundName, boundType); From 6a896f766a95e2894b19a97f055c89a754463333 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 23 Jan 2020 10:53:04 +0100 Subject: [PATCH 019/165] Function call options for YulIR. --- .../codegen/ir/IRGeneratorForStatements.cpp | 19 +++++++++++++++++++ .../codegen/ir/IRGeneratorForStatements.h | 1 + 2 files changed, 20 insertions(+) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 7ce1785b647c..e370acd7c82e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -739,6 +739,25 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } } +void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) +{ + FunctionType const& previousType = dynamic_cast(*_options.expression().annotation().type); + + solUnimplementedAssert(!previousType.bound(), ""); + + // Copy over existing values. + for (auto const& item: previousType.stackItems()) + define(IRVariable(_options).part(get<0>(item)), IRVariable(_options.expression()).part(get<0>(item))); + + for (size_t i = 0; i < _options.names().size(); ++i) + { + string const& name = *_options.names()[i]; + solAssert(name == "salt" || name == "gas" || name == "value", ""); + + define(IRVariable(_options).part(name), *_options.options()[i]); + } +} + void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { ASTString const& member = _memberAccess.memberName(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 785b02e098e6..39dbb67d77b9 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -60,6 +60,7 @@ class IRGeneratorForStatements: public ASTConstVisitor void endVisit(UnaryOperation const& _unaryOperation) override; bool visit(BinaryOperation const& _binOp) override; void endVisit(FunctionCall const& _funCall) override; + void endVisit(FunctionCallOptions const& _funCallOptions) override; void endVisit(MemberAccess const& _memberAccess) override; bool visit(InlineAssembly const& _inlineAsm) override; void endVisit(IndexAccess const& _indexAccess) override; From 5dd30777d2097d71bdffb3c17ccf6f734248465b Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 25 Feb 2020 17:58:11 +0100 Subject: [PATCH 020/165] Test. --- .../functionCall/external_call_value.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/libsolidity/semanticTests/functionCall/external_call_value.sol diff --git a/test/libsolidity/semanticTests/functionCall/external_call_value.sol b/test/libsolidity/semanticTests/functionCall/external_call_value.sol new file mode 100644 index 000000000000..47e2bfb764f3 --- /dev/null +++ b/test/libsolidity/semanticTests/functionCall/external_call_value.sol @@ -0,0 +1,17 @@ +pragma solidity >= 0.6.0; + +contract C { + function g(uint n) external payable returns (uint, uint) { + return (msg.value * 1000, n); + } + + function f(uint n) public payable returns (uint, uint) { + return this.g{value: 10}(n); + } +} + +// ==== +// compileViaYul: also +// ---- +// g(uint256), 1 ether: 4 -> 1000000000000000000000, 4 +// f(uint256), 11 ether: 2 -> 10000, 2 From 37878cf8d250856f2516475e597ad9f3335ca560 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Thu, 27 Feb 2020 16:47:20 +0100 Subject: [PATCH 021/165] Adding support for ipfs large files. --- Changelog.md | 3 +- libsolidity/interface/CompilerStack.cpp | 6 +- libsolutil/IpfsHash.cpp | 155 ++++++++++++++++++++---- test/libsolutil/IpfsHash.cpp | 53 ++++++-- 4 files changed, 179 insertions(+), 38 deletions(-) diff --git a/Changelog.md b/Changelog.md index 15221bb7d581..e92b536df52d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,12 +4,12 @@ Language Features: Compiler Features: + * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. Bugfixes: - ### 0.6.4 (2020-03-10) Language Features: @@ -30,7 +30,6 @@ Bugfixes: * SMTChecker: Fix internal errors when analysing tuples. * Yul AST Import: correctly import blocks as statements, switch statements and string literals. - ### 0.6.3 (2020-02-18) Language Features: diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 49b17cf337fd..781f68d6b185 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -899,8 +899,7 @@ h256 const& CompilerStack::Source::swarmHash() const string const& CompilerStack::Source::ipfsUrl() const { if (ipfsUrlCached.empty()) - if (scanner->source().size() < 1024 * 256) - ipfsUrlCached = "dweb:/ipfs/" + util::ipfsHashBase58(scanner->source()); + ipfsUrlCached = "dweb:/ipfs/" + util::ipfsHashBase58(scanner->source()); return ipfsUrlCached; } @@ -1373,10 +1372,7 @@ bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimen MetadataCBOREncoder encoder; if (m_metadataHash == MetadataHash::IPFS) - { - solAssert(_metadata.length() < 1024 * 256, "Metadata too large."); encoder.pushBytes("ipfs", util::ipfsHash(_metadata)); - } else if (m_metadataHash == MetadataHash::Bzzr1) encoder.pushBytes("bzzr1", util::bzzr1Hash(_metadata).asBytes()); else diff --git a/libsolutil/IpfsHash.cpp b/libsolutil/IpfsHash.cpp index d6a511a24011..95605cdc17d1 100644 --- a/libsolutil/IpfsHash.cpp +++ b/libsolutil/IpfsHash.cpp @@ -40,6 +40,21 @@ bytes varintEncoding(size_t _n) return encoded; } +bytes encodeByteArray(bytes const& _data) +{ + return bytes{0x0a} + varintEncoding(_data.size()) + _data; +} + +bytes encodeHash(bytes const& _data) +{ + return bytes{0x12, 0x20} + picosha2::hash256(_data); +} + +bytes encodeLinkData(bytes const& _data) +{ + return bytes{0x12} + varintEncoding(_data.size()) + _data; +} + string base58Encode(bytes const& _data) { static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"}; @@ -53,36 +68,132 @@ string base58Encode(bytes const& _data) reverse(output.begin(), output.end()); return output; } + +struct Chunk +{ + Chunk() = default; + Chunk(bytes _hash, size_t _size, size_t _blockSize): + hash(std::move(_hash)), + size(_size), + blockSize(_blockSize) + {} + + bytes hash = {}; + size_t size = 0; + size_t blockSize = 0; +}; + +using Chunks = vector; + +Chunk combineLinks(Chunks& _links) +{ + bytes data = {}; + bytes lengths = {}; + Chunk chunk = {}; + for (Chunk& link: _links) + { + chunk.size += link.size; + chunk.blockSize += link.blockSize; + + data += encodeLinkData( + bytes {0x0a} + + varintEncoding(link.hash.size()) + + std::move(link.hash) + + bytes{0x12, 0x00, 0x18} + + varintEncoding(link.blockSize) + ); + + lengths += bytes{0x20} + varintEncoding(link.size); + } + + bytes blockData = data + encodeByteArray(bytes{0x08, 0x02, 0x18} + varintEncoding(chunk.size) + lengths); + + chunk.blockSize += blockData.size(); + chunk.hash = encodeHash(blockData); + + return chunk; +} + +Chunks buildNextLevel(Chunks& _currentLevel) +{ + size_t const maxChildNum = 174; + + Chunks nextLevel; + Chunks links; + + for (Chunk& chunk: _currentLevel) + { + links.emplace_back(std::move(chunk.hash), chunk.size, chunk.blockSize); + if (links.size() == maxChildNum) + { + nextLevel.emplace_back(combineLinks(links)); + links = {}; + } + } + if (!links.empty()) + nextLevel.emplace_back(combineLinks(links)); + + return nextLevel; +} + +/// Builds a tree starting from the bottom level where nodes are data nodes. +/// Data nodes should be calculated and passed as the only level in chunk levels +/// Each next level is calculated as following: +/// - Pick up to maxChildNum (174) nodes until a whole level is added, group them and pass to the node in the next level +/// - Do this until the current level has only one node, return the hash in that node +bytes groupChunksBottomUp(Chunks _currentLevel) +{ + // when we reach root it will be the only node in that level + while (_currentLevel.size() != 1) + _currentLevel = buildNextLevel(_currentLevel); + + // top level's only node stores the hash for file + return _currentLevel.front().hash; +} } bytes solidity::util::ipfsHash(string _data) { - assertThrow(_data.length() < 1024 * 256, DataTooLong, "IPFS hash for large (chunked) files not yet implemented."); + size_t const maxChunkSize = 1024 * 256; + size_t chunkCount = _data.length() / maxChunkSize + (_data.length() % maxChunkSize > 0 ? 1 : 0); + chunkCount = chunkCount == 0 ? 1 : chunkCount; - bytes lengthAsVarint = varintEncoding(_data.size()); + Chunks allChunks; - bytes protobufEncodedData; - // Type: File - protobufEncodedData += bytes{0x08, 0x02}; - if (!_data.empty()) + for (unsigned long chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++) { - // Data (length delimited bytes) - protobufEncodedData += bytes{0x12}; - protobufEncodedData += lengthAsVarint; - protobufEncodedData += asBytes(std::move(_data)); + bytes chunkBytes = asBytes( + _data.substr(chunkIndex * maxChunkSize, min(maxChunkSize, _data.length() - chunkIndex * maxChunkSize)) + ); + + bytes lengthAsVarint = varintEncoding(chunkBytes.size()); + + bytes protobufEncodedData; + // Type: File + protobufEncodedData += bytes{0x08, 0x02}; + if (!chunkBytes.empty()) + { + // Data (length delimited bytes) + protobufEncodedData += bytes{0x12}; + protobufEncodedData += lengthAsVarint; + protobufEncodedData += chunkBytes; + } + // filesize: length as varint + protobufEncodedData += bytes{0x18} + lengthAsVarint; + + // PBDag: + // Data: (length delimited bytes) + bytes blockData = encodeByteArray(protobufEncodedData); + + // Multihash: sha2-256, 256 bits + allChunks.emplace_back( + encodeHash(blockData), + chunkBytes.size(), + blockData.size() + ); } - // filesize: length as varint - protobufEncodedData += bytes{0x18} + lengthAsVarint; - - // PBDag: - // Data: (length delimited bytes) - size_t protobufLength = protobufEncodedData.size(); - bytes blockData = bytes{0x0a} + varintEncoding(protobufLength) + std::move(protobufEncodedData); - // TODO Handle "large" files with multiple blocks - - // Multihash: sha2-256, 256 bits - bytes hash = bytes{0x12, 0x20} + picosha2::hash256(std::move(blockData)); - return hash; + + return groupChunksBottomUp(std::move(allChunks)); } string solidity::util::ipfsHashBase58(string _data) diff --git a/test/libsolutil/IpfsHash.cpp b/test/libsolutil/IpfsHash.cpp index 4514b2f4c0f3..9c4fb56332fd 100644 --- a/test/libsolutil/IpfsHash.cpp +++ b/test/libsolutil/IpfsHash.cpp @@ -60,15 +60,50 @@ BOOST_AUTO_TEST_CASE(test_largest_unchunked) BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmbNDspMkzkMFKyS3eCJGedG7GWRQHSCzJCZLjxP7wyVAx"); } -// TODO This needs chunking implemented -//BOOST_AUTO_TEST_CASE(test_large) -//{ -// size_t length = 1310710; -// string data; -// data.resize(length, 0); -// BOOST_REQUIRE_EQUAL(data.size(), length); -// BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmNg7BJo8gEMDK8yGQbHEwPtycesnE6FUULX5iVd5TAL9f"); -//} +BOOST_AUTO_TEST_CASE(test_smallest_chunked) +{ + size_t length = 1024 * 256 + 1; + string data; + data.resize(length, 0); + BOOST_REQUIRE_EQUAL(data.size(), length); + BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmbVuw4C4vcmVKqxoWtgDVobvcHrSn51qsmQmyxjk4sB2Q"); +} + +BOOST_AUTO_TEST_CASE(test_large) +{ + size_t length = 1310710; + string data; + data.resize(length, 0); + BOOST_REQUIRE_EQUAL(data.size(), length); + BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmNg7BJo8gEMDK8yGQbHEwPtycesnE6FUULX5iVd5TAL9f"); +} + +BOOST_AUTO_TEST_CASE(test_largest_one_level) +{ + size_t length = 45613056; // 1024 * 256 * 174; + string data; + data.resize(length, 0); + BOOST_REQUIRE_EQUAL(data.size(), length); + BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmY4HSz1oVGdUzb8poVYPLsoqBZjH6LZrtgnme9wWn2Qko"); +} + +BOOST_AUTO_TEST_CASE(test_smallest_multi_level) +{ + size_t length = 45613057; // 1024 * 256 * 174 + 1; + string data; + data.resize(length, 0); + BOOST_REQUIRE_EQUAL(data.size(), length); + BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmehMASWcBsX7VcEQqs6rpR5AHoBfKyBVEgmkJHjpPg8jq"); +} + +BOOST_AUTO_TEST_CASE(test_multi_level_tree) +{ + size_t length = 46661632; + string data; + data.resize(length, 0); + BOOST_REQUIRE_EQUAL(data.size(), length); + BOOST_CHECK_EQUAL(ipfsHashBase58(data), "QmaTb1sT9hrSXJLmf8bxJ9NuwndiHuMLsgNLgkS2eXu3Xj"); +} BOOST_AUTO_TEST_SUITE_END() From 07368c2e1e18577d7697275c347ba0e3f0cfcc41 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 11 Feb 2020 23:21:42 -0300 Subject: [PATCH 022/165] Add support to internal function calls --- Changelog.md | 1 + libsolidity/formal/BMC.cpp | 6 -- libsolidity/formal/CHC.cpp | 70 +++++++++++++++++-- libsolidity/formal/CHC.h | 3 + libsolidity/formal/SMTEncoder.cpp | 1 - .../short_circuit_and_inside_branch.sol | 14 ++-- .../functions/constructor_hierarchy_3.sol | 2 + .../constructor_hierarchy_diamond.sol | 2 + .../constructor_hierarchy_diamond_2.sol | 2 + .../constructor_hierarchy_diamond_3.sol | 3 + ...ctor_hierarchy_mixed_chain_with_params.sol | 1 + .../constructor_hierarchy_same_var.sol | 1 + ...unction_call_does_not_clear_local_vars.sol | 2 - .../functions/function_inline_chain.sol | 28 ++------ .../functions/functions_recursive.sol | 1 - .../functions_recursive_indirect.sol | 3 +- .../internal_call_with_assertion_1.sol | 25 +++++++ .../internal_call_with_assertion_1_fail.sol | 32 +++++++++ ...rnal_call_with_assertion_inheritance_1.sol | 21 ++++++ ...call_with_assertion_inheritance_1_fail.sol | 26 +++++++ ...ternal_multiple_calls_with_assertion_1.sol | 27 +++++++ ...l_multiple_calls_with_assertion_1_fail.sol | 30 ++++++++ .../functions/library_after_contract.sol | 18 +++++ .../functions/recursive_multi_return.sol | 1 - .../functions/recursive_multi_return_2.sol | 1 - ...ctor_hierarchy_mixed_chain_with_params.sol | 1 + ...ctor_state_variable_init_chain_run_all.sol | 6 ++ ...or_state_variable_init_chain_run_all_2.sol | 5 ++ ...ctor_state_variable_init_function_call.sol | 2 - .../invariants/loop_nested.sol | 7 +- .../invariants/loop_nested_for.sol | 6 -- .../loops/for_1_continue_fail.sol | 7 +- .../loops/for_1_false_positive.sol | 2 - ...or_loop_array_assignment_memory_memory.sol | 2 - .../loops/while_loop_simple_5.sol | 3 +- .../loops/while_nested_break_fail.sol | 2 - .../loops/while_nested_continue_fail.sol | 2 - .../modifier_code_after_placeholder.sol | 1 + .../modifier_multi_functions_recursive.sol | 3 - .../operators/delete_array_index_2d.sol | 6 +- .../smtCheckerTests/special/many.sol | 1 + ...unction_type_to_function_type_internal.sol | 20 ++++-- ...g_literal_to_fixed_bytes_function_call.sol | 1 - .../types/array_aliasing_memory_1.sol | 26 ++++--- .../types/array_aliasing_memory_2.sol | 9 +-- .../types/array_aliasing_memory_3.sol | 9 +-- .../types/array_aliasing_storage_1.sol | 35 ++++++---- .../types/array_aliasing_storage_2.sol | 12 +++- .../types/array_aliasing_storage_3.sol | 13 +++- .../types/array_aliasing_storage_4.sol | 14 ++-- .../types/array_aliasing_storage_5.sol | 21 ++++-- .../types/array_mapping_aliasing_1.sol | 15 ++-- .../types/array_mapping_aliasing_2.sol | 12 ++-- .../types/array_static_aliasing_memory_5.sol | 6 +- .../types/array_static_aliasing_storage_5.sol | 21 ++++-- .../types/array_static_mapping_aliasing_1.sol | 15 ++-- .../types/array_static_mapping_aliasing_2.sol | 12 ++-- .../smtCheckerTests/types/enum_in_library.sol | 2 +- .../types/enum_in_library_2.sol | 4 +- .../smtCheckerTests/types/enum_in_struct.sol | 17 ++--- .../smtCheckerTests/types/fixed_bytes_2.sol | 15 ++++ .../types/mapping_aliasing_1.sol | 7 +- .../types/mapping_aliasing_2.sol | 27 +++++-- .../types/string_literal_comparison_2.sol | 1 + .../smtCheckerTests/types/tuple_function.sol | 1 + .../types/tuple_function_3.sol | 1 + .../smtCheckerTestsJSON/multi.json | 2 +- 67 files changed, 506 insertions(+), 189 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/library_after_contract.sol create mode 100644 test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol diff --git a/Changelog.md b/Changelog.md index 15221bb7d581..7dfb7a3e3a8b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -44,6 +44,7 @@ Compiler Features: * Code Generator: Use ``calldatacopy`` instead of ``codecopy`` to zero out memory past input. * Debug: Provide reason strings for compiler-generated internal reverts when using the ``--revert-strings`` option or the ``settings.debug.revertStrings`` setting on ``debug`` mode. * Yul Optimizer: Prune functions that call each other but are otherwise unreferenced. + * SMTChecker: CHC support to internal function calls. Bugfixes: diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index dd1e5136cd40..141a3eb32d3d 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -432,12 +432,6 @@ void BMC::inlineFunctionCall(FunctionCall const& _funCall) m_context.newValue(*param); m_context.setUnknownValue(*param); } - - m_errorReporter.warning( - _funCall.location(), - "Assertion checker does not support recursive function calls.", - SecondarySourceLocation().append("Starting from function:", funDef->location()) - ); } else { diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index af50b27226e8..1e851937c4a1 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -459,6 +459,8 @@ void CHC::endVisit(FunctionCall const& _funCall) SMTEncoder::endVisit(_funCall); break; case FunctionType::Kind::Internal: + internalFunctionCall(_funCall); + break; case FunctionType::Kind::External: case FunctionType::Kind::DelegateCall: case FunctionType::Kind::BareCall: @@ -525,6 +527,39 @@ void CHC::visitAssert(FunctionCall const& _funCall) m_context.addAssertion(m_error.currentValue() == previousError); } +void CHC::internalFunctionCall(FunctionCall const& _funCall) +{ + solAssert(m_currentContract, ""); + + auto const* function = functionCallToDefinition(_funCall); + if (function) + { + if (m_currentFunction && !m_currentFunction->isConstructor()) + m_callGraph[m_currentFunction].insert(function); + else + m_callGraph[m_currentContract].insert(function); + auto const* contract = function->annotation().contract; + + // Libraries can have constants as their "state" variables, + // so we need to ensure they were constructed correctly. + if (contract->isLibrary()) + m_context.addAssertion(interface(*contract)); + } + + auto previousError = m_error.currentValue(); + + m_context.addAssertion(predicate(_funCall)); + + connectBlocks( + m_currentBlock, + (m_currentFunction && !m_currentFunction->isConstructor()) ? summary(*m_currentFunction) : summary(*m_currentContract), + (m_error.currentValue() > 0) + ); + m_context.addAssertion(m_error.currentValue() == 0); + m_error.increaseIndex(); + m_context.addAssertion(m_error.currentValue() == previousError); +} + void CHC::unknownFunctionCall(FunctionCall const&) { /// Function calls are not handled at the moment, @@ -580,12 +615,7 @@ void CHC::clearIndices(ContractDefinition const* _contract, FunctionDefinition c bool CHC::shouldVisit(FunctionDefinition const& _function) const { - if ( - _function.isPublic() && - _function.isImplemented() - ) - return true; - return false; + return _function.isImplemented(); } void CHC::setCurrentBlock( @@ -919,6 +949,34 @@ smt::Expression CHC::predicate( return _block(_arguments); } +smt::Expression CHC::predicate(FunctionCall const& _funCall) +{ + auto const* function = functionCallToDefinition(_funCall); + if (!function) + return smt::Expression(true); + + m_error.increaseIndex(); + vector args{m_error.currentValue()}; + auto const* contract = function->annotation().contract; + + args += contract->isLibrary() ? stateVariablesAtIndex(0, *contract) : currentStateVariables(); + args += symbolicArguments(_funCall); + for (auto const& var: m_stateVariables) + m_context.variable(*var)->increaseIndex(); + args += contract->isLibrary() ? stateVariablesAtIndex(1, *contract) : currentStateVariables(); + + auto const& returnParams = function->returnParameters(); + for (auto param: returnParams) + if (m_context.knownVariable(*param)) + m_context.variable(*param)->increaseIndex(); + else + createVariable(*param); + for (auto const& var: function->returnParameters()) + args.push_back(m_context.variable(*var)->currentValue()); + + return (*m_summaries.at(contract).at(function))(args); +} + void CHC::addRule(smt::Expression const& _rule, string const& _ruleName) { m_interface->addRule(_rule, _ruleName); diff --git a/libsolidity/formal/CHC.h b/libsolidity/formal/CHC.h index 889c21b6aa35..4f601a2d51b9 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -76,6 +76,7 @@ class CHC: public SMTEncoder void endVisit(Continue const& _node) override; void visitAssert(FunctionCall const& _funCall); + void internalFunctionCall(FunctionCall const& _funCall); void unknownFunctionCall(FunctionCall const& _funCall); //@} @@ -164,6 +165,8 @@ class CHC: public SMTEncoder smt::Expression predicate(smt::SymbolicFunctionVariable const& _block); /// @returns a predicate application over @param _arguments. smt::Expression predicate(smt::SymbolicFunctionVariable const& _block, std::vector const& _arguments); + /// @returns the summary predicate for the called function. + smt::Expression predicate(FunctionCall const& _funCall); /// @returns a predicate that defines a constructor summary. smt::Expression summary(ContractDefinition const& _contract); /// @returns a predicate that defines a function summary. diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 3b2f48816589..0efaf90a9bdb 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -673,7 +673,6 @@ void SMTEncoder::visitAssert(FunctionCall const& _funCall) auto const& args = _funCall.arguments(); solAssert(args.size() == 1, ""); solAssert(args.front()->annotation().type->category() == Type::Category::Bool, ""); - addPathImpliedExpression(expr(*args.front())); } void SMTEncoder::visitRequire(FunctionCall const& _funCall) diff --git a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol index f49a572cfa47..290d738726c3 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/short_circuit_and_inside_branch.sol @@ -6,23 +6,17 @@ contract c { x = x + 1; return x; } - function g(bool a) public returns (bool) { + function g() public returns (bool) { bool b; - if (a) { - x = 0; - b = (f() == 0) && (f() == 0); - assert(x == 1); - assert(!b); - } else { x = 100; - b = (f() > 0) && (f() > 0); + b = f() > 0; assert(x == 102); // Should fail. assert(!b); - } return b; } } // ---- // Warning: (101-106): Overflow (resulting value larger than 2**256 - 1) happens here -// Warning: (362-372): Assertion violation happens here +// Warning: (202-218): Assertion violation happens here +// Warning: (242-252): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol index 79acf49d7628..f6e32d10a8a1 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_3.sol @@ -19,4 +19,6 @@ contract A is B { } } // ---- +// Warning: (217-222): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (265-270): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (253-271): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol index 5b339e0049f1..79f0c03dc02c 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond.sol @@ -26,4 +26,6 @@ contract A is B2, B1 { } // ---- // Warning: (214-219): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (214-219): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (342-347): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (330-348): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol index c0bf299f8e69..d33247a0e346 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_2.sol @@ -26,4 +26,6 @@ contract A is B2, B1 { } // ---- // Warning: (214-219): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (214-219): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (342-347): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (330-348): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol index 4ad9083fa84f..b5428d15b44e 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_diamond_3.sol @@ -31,4 +31,7 @@ contract A is B2, B1 { // Warning: (174-179): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (239-244): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (262-267): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (239-244): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (262-267): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (174-179): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (362-378): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol index 6959f6c8861d..b6363f8efaf0 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_mixed_chain_with_params.sol @@ -26,4 +26,5 @@ contract A is B { } // ---- // Warning: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (356-370): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol index a607a9556d18..c4dbe02191bc 100644 --- a/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol +++ b/test/libsolidity/smtCheckerTests/functions/constructor_hierarchy_same_var.sol @@ -14,3 +14,4 @@ contract A is C { } // ---- // Warning: (148-162): Assertion violation happens here +// Warning: (166-182): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol b/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol index ee4504287264..1f002796f38f 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_call_does_not_clear_local_vars.sol @@ -9,5 +9,3 @@ contract C { } } // ---- -// Warning: (99-107): Assertion checker does not support recursive function calls. -// Warning: (141-144): Assertion checker does not support recursive function calls. diff --git a/test/libsolidity/smtCheckerTests/functions/function_inline_chain.sol b/test/libsolidity/smtCheckerTests/functions/function_inline_chain.sol index 2647e0771d71..dd3924e2971d 100644 --- a/test/libsolidity/smtCheckerTests/functions/function_inline_chain.sol +++ b/test/libsolidity/smtCheckerTests/functions/function_inline_chain.sol @@ -2,40 +2,22 @@ pragma experimental SMTChecker; contract C { - uint x; uint y; - uint z; function f() public { - if (x == 1) - x = 2; - else - x = 1; - g(); + if (y != 1) + g(); assert(y == 1); } - function g() public { + function g() internal { y = 1; h(); - assert(z == 1); } - function h() public { - z = 1; - x = 1; + function h() internal { f(); - // This fails for the following calls to the contract: - // h() - // g() h() - // It does not fail for f() g() h() because in that case - // h() will not inline f() since it already is in the callstack. - assert(x == 1); + assert(y == 1); } } // ---- -// Warning: (271-274): Assertion checker does not support recursive function calls. -// Warning: (140-143): Assertion checker does not support recursive function calls. -// Warning: (483-497): Assertion violation happens here -// Warning: (201-204): Assertion checker does not support recursive function calls. -// Warning: (483-497): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/functions_recursive.sol b/test/libsolidity/smtCheckerTests/functions/functions_recursive.sol index d2f8ab1db514..ee24f0ae5687 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_recursive.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_recursive.sol @@ -14,4 +14,3 @@ contract C } // ---- -// Warning: (111-114): Assertion checker does not support recursive function calls. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol b/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol index d5b83f007aa6..5d3292992ad3 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_recursive_indirect.sol @@ -22,5 +22,4 @@ contract C } } // ---- -// Warning: (206-209): Assertion checker does not support recursive function calls. -// Warning: (111-114): Assertion checker does not support recursive function calls. +// Warning: (130-144): Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol new file mode 100644 index 000000000000..e17e384ddc7e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1.sol @@ -0,0 +1,25 @@ +pragma experimental SMTChecker; + +contract C{ + uint x; + constructor(uint y) public { + assert(x == 0); + x = 1; + } + function f() public { + assert(x == 1); + ++x; + g(); + assert(x == 1); + } + + function g() internal { + assert(x == 2); + --x; + assert(x == 1); + } +} +// ---- +// Warning: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. +// Warning: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (245-248): Underflow (resulting value less than 0) happens here diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol new file mode 100644 index 000000000000..3f765ecd29f0 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_1_fail.sol @@ -0,0 +1,32 @@ +pragma experimental SMTChecker; + +contract C{ + uint x; + constructor(uint y) public { + assert(x == 1); + x = 1; + } + function f() public { + assert(x == 2); + ++x; + g(); + assert(x == 2); + } + + function g() internal { + assert(x == 3); + --x; + assert(x == 2); + } +} +// ---- +// Warning: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. +// Warning: (145-159): Assertion violation happens here +// Warning: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (227-241): Assertion violation happens here +// Warning: (252-266): Assertion violation happens here +// Warning: (177-191): Assertion violation happens here +// Warning: (227-241): Assertion violation happens here +// Warning: (245-248): Underflow (resulting value less than 0) happens here +// Warning: (252-266): Assertion violation happens here +// Warning: (89-103): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol new file mode 100644 index 000000000000..0d2a3c79476f --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1.sol @@ -0,0 +1,21 @@ +pragma experimental SMTChecker; + +contract A { + uint x; + function f() internal { + assert(x == 1); + --x; + } +} + +contract C is A { + constructor() public { + assert(x == 0); + ++x; + f(); + assert(x == 0); + } +} +// ---- +// Warning: (100-103): Underflow (resulting value less than 0) happens here +// Warning: (100-103): Underflow (resulting value less than 0) happens here diff --git a/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol new file mode 100644 index 000000000000..da8dec6a204b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_call_with_assertion_inheritance_1_fail.sol @@ -0,0 +1,26 @@ +pragma experimental SMTChecker; + +contract A { + uint x; + function f() internal { + assert(x == 2); + --x; + } +} + +contract C is A { + constructor() public { + assert(x == 1); + ++x; + f(); + assert(x == 1); + } +} +// ---- +// Warning: (82-96): Assertion violation happens here +// Warning: (100-103): Underflow (resulting value less than 0) happens here +// Warning: (82-96): Assertion violation happens here +// Warning: (100-103): Underflow (resulting value less than 0) happens here +// Warning: (155-169): Assertion violation happens here +// Warning: (82-96): Assertion violation happens here +// Warning: (187-201): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol new file mode 100644 index 000000000000..b052f5070870 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1.sol @@ -0,0 +1,27 @@ +pragma experimental SMTChecker; + +contract C{ + uint x; + constructor(uint y) public { + assert(x == 0); + x = 1; + } + function f() public { + assert(x == 1); + ++x; + ++x; + g(); + g(); + assert(x == 1); + } + + function g() internal { + --x; + } +} +// ---- +// Warning: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. +// Warning: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (170-173): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (241-244): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (241-244): Underflow (resulting value less than 0) happens here diff --git a/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol new file mode 100644 index 000000000000..cb50a931e699 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/internal_multiple_calls_with_assertion_1_fail.sol @@ -0,0 +1,30 @@ +pragma experimental SMTChecker; + +contract C{ + uint x; + constructor(uint y) public { + assert(x == 1); + x = 1; + } + function f() public { + assert(x == 2); + ++x; + ++x; + g(); + g(); + assert(x == 3); + } + + function g() internal { + --x; + } +} +// ---- +// Warning: (70-76): Unused function parameter. Remove or comment out the variable name to silence this warning. +// Warning: (145-159): Assertion violation happens here +// Warning: (163-166): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (170-173): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (241-244): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (191-205): Assertion violation happens here +// Warning: (241-244): Underflow (resulting value less than 0) happens here +// Warning: (89-103): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/functions/library_after_contract.sol b/test/libsolidity/smtCheckerTests/functions/library_after_contract.sol new file mode 100644 index 000000000000..5e69f7830b2d --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/library_after_contract.sol @@ -0,0 +1,18 @@ +pragma experimental SMTChecker; + +contract C { + function g(uint y) public { + uint z = L.f(y); + assert(z == y); + } +} + +library L { + function f(uint x) internal returns (uint) { + return x; + } +} + +// ---- +// Warning: (131-190): Function state mutability can be restricted to pure +// Warning: (86-87): Assertion checker does not yet implement type type(library L) diff --git a/test/libsolidity/smtCheckerTests/functions/recursive_multi_return.sol b/test/libsolidity/smtCheckerTests/functions/recursive_multi_return.sol index 17cf6ea64e9b..0c2a781fca9d 100644 --- a/test/libsolidity/smtCheckerTests/functions/recursive_multi_return.sol +++ b/test/libsolidity/smtCheckerTests/functions/recursive_multi_return.sol @@ -9,4 +9,3 @@ contract C { } // // ---- -// Warning: (126-129): Assertion checker does not support recursive function calls. diff --git a/test/libsolidity/smtCheckerTests/functions/recursive_multi_return_2.sol b/test/libsolidity/smtCheckerTests/functions/recursive_multi_return_2.sol index 22b956584aa4..00f78df3cc6c 100644 --- a/test/libsolidity/smtCheckerTests/functions/recursive_multi_return_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/recursive_multi_return_2.sol @@ -25,4 +25,3 @@ a; // ---- // Warning: (72-90): Statement has no effect. // Warning: (96-107): Statement has no effect. -// Warning: (304-307): Assertion checker does not support recursive function calls. diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol index 6959f6c8861d..b6363f8efaf0 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_hierarchy_mixed_chain_with_params.sol @@ -26,4 +26,5 @@ contract A is B { } // ---- // Warning: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (356-370): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol index 82d411e47b8d..7be0676d2c72 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all.sol @@ -24,4 +24,10 @@ contract A is B { // ---- // Warning: (171-176): Underflow (resulting value less than 0) happens here // Warning: (171-176): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (230-235): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (171-176): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (260-265): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (282-287): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (282-291): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (308-313): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (296-314): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol index fc6643a4292a..ff316ce477e9 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_chain_run_all_2.sol @@ -23,4 +23,9 @@ contract A is B { // ---- // Warning: (171-177): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (231-236): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (171-177): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (261-266): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (283-289): Overflow (resulting value larger than 2**256 - 1) happens here +// Warning: (306-311): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (294-312): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_function_call.sol b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_function_call.sol index 91798ec0cbc0..36c8ce55186a 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_function_call.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/constructor_state_variable_init_function_call.sol @@ -13,5 +13,3 @@ contract C { } } // ---- -// Warning: (162-175): Assertion violation happens here -// Warning: (179-193): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol b/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol index 1fb380649f38..6303158f7ef5 100644 --- a/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol +++ b/test/libsolidity/smtCheckerTests/invariants/loop_nested.sol @@ -1,5 +1,8 @@ pragma experimental SMTChecker; +// This test gets different results on Linux and OSX. +// Re-enable when fixed (SMTSolvers: z3) + contract Simple { function f() public pure { uint x = 10; @@ -16,9 +19,7 @@ contract Simple { } } // ==== -// SMTSolvers: z3 +// SMTSolvers: none // ---- -// Warning: (172-187): Error trying to invoke SMT solver. // Warning: (195-209): Error trying to invoke SMT solver. -// Warning: (172-187): Assertion violation happens here // Warning: (195-209): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/invariants/loop_nested_for.sol b/test/libsolidity/smtCheckerTests/invariants/loop_nested_for.sol index e7fde4d5aa28..ea1c54851e1a 100644 --- a/test/libsolidity/smtCheckerTests/invariants/loop_nested_for.sol +++ b/test/libsolidity/smtCheckerTests/invariants/loop_nested_for.sol @@ -12,10 +12,4 @@ contract Simple { assert(y == x); } } -// ==== -// SMTSolvers: z3 // ---- -// Warning: (164-179): Error trying to invoke SMT solver. -// Warning: (187-201): Error trying to invoke SMT solver. -// Warning: (164-179): Assertion violation happens here -// Warning: (187-201): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol b/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol index 7f73f86c10a5..4b97a7ea0b4e 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_continue_fail.sol @@ -5,10 +5,6 @@ contract C function f(uint x, bool b) public pure { require(x < 10); for (; x < 10; ) { - if (b) { - x = 20; - continue; - } ++x; } assert(x > 15); @@ -17,4 +13,5 @@ contract C // ==== // SMTSolvers: z3 // ---- -// Warning: (185-199): Assertion violation happens here +// Warning: (66-72): Unused function parameter. Remove or comment out the variable name to silence this warning. +// Warning: (142-156): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol index e57c62313b36..11cd22d11840 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_1_false_positive.sol @@ -13,8 +13,6 @@ contract C assert(x > 0); } } -// ==== -// SMTSolvers: z3 // ---- // Warning: (296-309): Error trying to invoke SMT solver. // Warning: (176-181): Overflow (resulting value larger than 2**256 - 1) happens here diff --git a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol index 1a9216de04a9..0694493f52c7 100644 --- a/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol +++ b/test/libsolidity/smtCheckerTests/loops/for_loop_array_assignment_memory_memory.sol @@ -14,8 +14,6 @@ contract LoopFor2 { assert(b[0] == 900); } } -// ==== -// SMTSolvers: z3 // ---- // Warning: (281-301): Assertion violation happens here // Warning: (305-324): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol index c85e7e3fb1b6..e022e0f299ba 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_loop_simple_5.sol @@ -4,6 +4,7 @@ contract C { function f(uint x, uint y) public pure { x = 7; while ((x = y) > 0) { + --y; } assert(x == 7); } @@ -11,4 +12,4 @@ contract C { // ==== // SMTSolvers: z3 // ---- -// Warning: (216-230): Assertion violation happens here +// Warning: (224-238): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol index e9752b3a8d33..986e7205b764 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_nested_break_fail.sol @@ -28,8 +28,6 @@ contract C assert(x >= 20); } } -// ==== -// SMTSolvers: z3 // ---- // Warning: (329-344): Assertion violation happens here // Warning: (380-395): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol b/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol index 4447cf6d74fd..71238c3be6e5 100644 --- a/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol +++ b/test/libsolidity/smtCheckerTests/loops/while_nested_continue_fail.sol @@ -26,8 +26,6 @@ contract C assert(x >= 20); } } -// ==== -// SMTSolvers: z3 // ---- // Warning: (323-338): Assertion violation happens here // Warning: (362-377): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol index 7a420c28f82c..702c24f4b612 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_code_after_placeholder.sol @@ -21,4 +21,5 @@ contract C } } // ---- +// Warning: (203-208): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (136-149): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions_recursive.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions_recursive.sol index b01fe812e509..16d071fdb4f7 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions_recursive.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_multi_functions_recursive.sol @@ -17,6 +17,3 @@ contract C } } // ---- -// Warning: (86-93): Assertion checker does not support recursive function calls. -// Warning: (86-93): Assertion checker does not support recursive function calls. -// Warning: (253-266): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol b/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol index 9cd7de9e67ba..8a1ba5e6ef90 100644 --- a/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol +++ b/test/libsolidity/smtCheckerTests/operators/delete_array_index_2d.sol @@ -4,7 +4,7 @@ contract C { uint[][] a; function f(bool b) public { - require(a[2][3] == 4); + a[2][3] = 4; if (b) delete a; else @@ -13,5 +13,7 @@ contract C assert(a[1][1] == 0); } } +// ==== +// SMTSolvers: z3 // ---- -// Warning: (184-204): Assertion violation happens here +// Warning: (174-194): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/special/many.sol b/test/libsolidity/smtCheckerTests/special/many.sol index e9ef98b26868..a8ae53997a8e 100644 --- a/test/libsolidity/smtCheckerTests/special/many.sol +++ b/test/libsolidity/smtCheckerTests/special/many.sol @@ -20,6 +20,7 @@ contract C // Warning: (165-204): Assertion violation happens here // Warning: (208-240): Assertion violation happens here // Warning: (244-275): Assertion violation happens here +// Warning: (311-316): Overflow (resulting value larger than 2**256 - 1) happens here // Warning: (304-332): Assertion violation happens here // Warning: (336-352): Assertion violation happens here // Warning: (356-379): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol index 1657a95c6dc9..abee678c0503 100644 --- a/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol +++ b/test/libsolidity/smtCheckerTests/typecast/function_type_to_function_type_internal.sol @@ -1,13 +1,23 @@ pragma experimental SMTChecker; contract C { + function(uint) returns (uint) a; + function(uint) returns (uint) b; function f(function(uint) returns (uint) g, function(uint) returns (uint) h) internal { assert(g(2) == h(2)); assert(g == h); } + function g() public { + f(a, b); + } } // ---- -// Warning: (146-150): Assertion checker does not yet implement this type of function call. -// Warning: (154-158): Assertion checker does not yet implement this type of function call. -// Warning: (170-176): Assertion checker does not yet implement the type function (uint256) returns (uint256) for comparisons -// Warning: (139-159): Assertion violation happens here -// Warning: (163-177): Assertion violation happens here +// Warning: (214-218): Assertion checker does not yet implement this type of function call. +// Warning: (222-226): Assertion checker does not yet implement this type of function call. +// Warning: (238-244): Assertion checker does not yet implement the type function (uint256) returns (uint256) for comparisons +// Warning: (207-227): Assertion violation happens here +// Warning: (231-245): Assertion violation happens here +// Warning: (214-218): Assertion checker does not yet implement this type of function call. +// Warning: (222-226): Assertion checker does not yet implement this type of function call. +// Warning: (238-244): Assertion checker does not yet implement the type function (uint256) returns (uint256) for comparisons +// Warning: (207-227): Assertion violation happens here +// Warning: (231-245): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol index b2701fdf9cfc..d94f3204b9ef 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_function_call.sol @@ -10,5 +10,4 @@ contract B { } // ---- // Warning: (162-184): Assertion violation happens here -// Warning: (136-158): Assertion violation happens here // Warning: (162-184): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol index 8cd4686529d3..00d2965bc9f2 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_1.sol @@ -1,4 +1,5 @@ pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; contract C { @@ -8,24 +9,21 @@ contract C uint[][] memory cc, uint8[][] memory dd, uint[][][] memory eee - ) internal pure { - require(a[0] == 2); - require(cc[0][0] == 50); - require(dd[0][0] == 10); - require(eee[0][0][0] == 50); + ) public pure { + a[0] = 2; + cc[0][0] = 50; + dd[0][0] = 10; + eee[0][0][0] = 50; b[0] = 1; - // Fails because b == a is possible. - assert(a[0] == 2); - // Fails because b == cc[0] is possible. - assert(cc[0][0] == 50); + // Fails because + // b == a is possible + // b == cc[0] is possible + // b == ee[0][0] is possible + assert(a[0] == 2 || cc[0][0] == 50 || eee[0][0][0] == 50); // Should not fail since knowledge is erased only for uint[]. assert(dd[0][0] == 10); - // Fails because b == ee[0][0] is possible. - assert(eee[0][0][0] == 50); assert(b[0] == 1); } } // ---- -// Warning: (345-362): Assertion violation happens here -// Warning: (409-431): Assertion violation happens here -// Warning: (571-597): Assertion violation happens here +// Warning: (400-457): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol index d015d147173b..94e7ccfcf633 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_2.sol @@ -1,11 +1,12 @@ pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; contract C { uint[] array; - function f(uint[] memory a, uint[] memory b) internal view { - require(array[0] == 42); - require(a[0] == 2); + function f(uint[] memory a, uint[] memory b) public { + array[0] = 42; + a[0] = 2; b[0] = 1; // Erasing knowledge about memory references should not // erase knowledge about state variables. @@ -15,4 +16,4 @@ contract C } } // ---- -// Warning: (314-331): Assertion violation happens here +// Warning: (321-338): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol index f6d6b1977d66..1ae2b935613a 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_memory_3.sol @@ -1,12 +1,13 @@ pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; contract C { uint[] array; - function f(uint[] memory a, uint[] memory b) internal view { - require(array[0] == 42); + function f(uint[] memory a, uint[] memory b) public { + array[0] = 42; uint[] storage c = array; - require(a[0] == 2); + a[0] = 2; b[0] = 1; // Erasing knowledge about memory references should not // erase knowledge about state variables. @@ -19,4 +20,4 @@ contract C } } // ---- -// Warning: (469-486): Assertion violation happens here +// Warning: (476-493): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol index 6461634e1161..2aacc5c0d9fa 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_1.sol @@ -4,7 +4,9 @@ contract C { uint[] array; uint[][] array2d; + uint[][][][] array4d; uint8[] tinyArray; + uint8[][][] tinyArray3d; function f( uint[] storage a, uint[] storage b, @@ -12,13 +14,13 @@ contract C uint8[][] storage dd, uint[][][] storage eee ) internal { - require(a[0] == 2); - require(array[0] == 42); - require(array2d[0][0] == 42); - require(tinyArray[0] == 42); - require(cc[0][0] == 42); - require(dd[0][0] == 42); - require(eee[0][0][0] == 42); + a[0] = 2; + array[0] = 42; + array2d[0][0] = 42; + tinyArray[0] = 42; + cc[0][0] = 42; + dd[0][0] = 42; + eee[0][0][0] = 42; b[0] = 1; // Fails because b == a is possible. assert(a[0] == 2); @@ -36,10 +38,19 @@ contract C assert(eee[0][0][0] == 42); assert(b[0] == 1); } + + function g(uint a, uint b, uint c, uint d, uint e) public { + f(array2d[a], array2d[b], array4d[c][c], tinyArray3d[d], array4d[e]); + } } // ---- -// Warning: (489-506): Assertion violation happens here -// Warning: (553-575): Assertion violation happens here -// Warning: (627-654): Assertion violation happens here -// Warning: (795-817): Assertion violation happens here -// Warning: (957-983): Assertion violation happens here +// Warning: (468-485): Assertion violation happens here +// Warning: (532-554): Assertion violation happens here +// Warning: (606-633): Assertion violation happens here +// Warning: (774-796): Assertion violation happens here +// Warning: (936-962): Assertion violation happens here +// Warning: (468-485): Assertion violation happens here +// Warning: (532-554): Assertion violation happens here +// Warning: (606-633): Assertion violation happens here +// Warning: (774-796): Assertion violation happens here +// Warning: (936-962): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol index 4b134e58e333..3d60c836a896 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_2.sol @@ -2,9 +2,14 @@ pragma experimental SMTChecker; contract C { + uint[][] array2d; + function g(uint x, uint y, uint[] memory c) public { + f(array2d[x], array2d[y], c); + } + function f(uint[] storage a, uint[] storage b, uint[] memory c) internal { - require(c[0] == 42); - require(a[0] == 2); + c[0] = 42; + a[0] = 2; b[0] = 1; // Erasing knowledge about storage references should not // erase knowledge about memory references. @@ -15,4 +20,5 @@ contract C } } // ---- -// Warning: (347-364): Assertion violation happens here +// Warning: (436-453): Assertion violation happens here +// Warning: (436-453): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol index d70cc18bbf64..68438eb6dcbe 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_3.sol @@ -2,10 +2,14 @@ pragma experimental SMTChecker; contract C { + uint[][] array2d; + function g(uint x, uint y, uint[] memory c) public { + f(array2d[x], array2d[y], c); + } function f(uint[] storage a, uint[] storage b, uint[] memory c) internal { uint[] memory d = c; - require(c[0] == 42); - require(a[0] == 2); + c[0] = 42; + a[0] = 2; b[0] = 1; // Erasing knowledge about storage references should not // erase knowledge about memory references. @@ -19,4 +23,7 @@ contract C } } // ---- -// Warning: (497-514): Assertion violation happens here +// Warning: (524-542): Assertion violation happens here +// Warning: (585-602): Assertion violation happens here +// Warning: (524-542): Assertion violation happens here +// Warning: (585-602): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol index 13dc6fcc2ba3..384a89b4fe6e 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_4.sol @@ -3,9 +3,10 @@ pragma experimental SMTChecker; contract C { uint[] array; + uint[][] array2d; function f(uint[] storage a, uint[] storage b) internal { - require(a[0] == 2); - require(b[0] == 42); + a[0] = 2; + b[0] = 42; array[0] = 1; // Fails because array == a is possible. assert(a[0] == 2); @@ -13,7 +14,12 @@ contract C assert(b[0] == 42); assert(array[0] == 1); } + function g(uint x, uint y) public { + f(array2d[x], array2d[y]); + } } // ---- -// Warning: (226-243): Assertion violation happens here -// Warning: (290-308): Assertion violation happens here +// Warning: (225-242): Assertion violation happens here +// Warning: (289-307): Assertion violation happens here +// Warning: (225-242): Assertion violation happens here +// Warning: (289-307): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol index ff47cc0e469d..e94ad4580419 100644 --- a/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_aliasing_storage_5.sol @@ -4,20 +4,29 @@ contract C { uint[] b; uint[] d; + uint[][] array2d; + function g(uint x, uint[] memory c) public { + f(array2d[x], c); + } function f(uint[] storage a, uint[] memory c) internal { - require(d[0] == 42); - require(c[0] == 42); - require(a[0] == 2); + d[0] = 42; + c[0] = 42; + a[0] = 2; b[0] = 1; // Erasing knowledge about storage variables should not // erase knowledge about memory references. assert(c[0] == 42); - // Should not fail since b == d is not possible. + // Fails because d == a is possible. assert(d[0] == 42); - // Fails because b == a is possible. + // Fails because b == a and d == a are possible. assert(a[0] == 2); + // b == a is possible, but does not fail because b + // was the last assignment. assert(b[0] == 1); } } // ---- -// Warning: (446-463): Assertion violation happens here +// Warning: (431-449): Assertion violation happens here +// Warning: (504-521): Assertion violation happens here +// Warning: (431-449): Assertion violation happens here +// Warning: (504-521): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol index 062e9776d335..dc69dd55aa29 100644 --- a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_1.sol @@ -7,9 +7,9 @@ contract C mapping (uint => uint8)[] severalMaps8; mapping (uint => uint)[][] severalMaps3d; function f(mapping (uint => uint) storage map) internal { - require(severalMaps[0][0] == 42); - require(severalMaps8[0][0] == 42); - require(severalMaps3d[0][0][0] == 42); + severalMaps[0][0] = 42; + severalMaps8[0][0] = 42; + severalMaps3d[0][0][0] = 42; map[0] = 2; // Should fail since map == severalMaps[0] is possible. assert(severalMaps[0][0] == 42); @@ -18,7 +18,12 @@ contract C // Should fail since map == severalMaps3d[0][0] is possible. assert(severalMaps3d[0][0][0] == 42); } + function g(uint x) public { + f(severalMaps[x]); + } } // ---- -// Warning: (451-482): Assertion violation happens here -// Warning: (665-701): Assertion violation happens here +// Warning: (421-452): Assertion violation happens here +// Warning: (635-671): Assertion violation happens here +// Warning: (421-452): Assertion violation happens here +// Warning: (635-671): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol index 1d5ab2687e9b..2e16e7b5da3c 100644 --- a/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_mapping_aliasing_2.sol @@ -8,9 +8,9 @@ contract C mapping (uint => uint)[][] severalMaps3d; function f(mapping (uint => uint) storage map) internal { map[0] = 42; - require(severalMaps[0][0] == 42); - require(severalMaps8[0][0] == 42); - require(severalMaps3d[0][0][0] == 42); + severalMaps[0][0] = 42; + severalMaps8[0][0] = 42; + severalMaps3d[0][0][0] = 42; singleMap[0] = 2; // Should not fail since singleMap == severalMaps[0] is not possible. assert(severalMaps[0][0] == 42); @@ -21,6 +21,10 @@ contract C // Should fail since singleMap == map is possible. assert(map[0] == 42); } + function g(uint x) public { + f(severalMaps[x]); + } } // ---- -// Warning: (807-827): Assertion violation happens here +// Warning: (777-797): Assertion violation happens here +// Warning: (777-797): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol index 99e993032efc..dd846b483a3a 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_memory_5.sol @@ -2,7 +2,7 @@ pragma experimental SMTChecker; contract C { - function f(uint[2] memory a, uint[2] memory b, uint[2] memory c) internal pure { + function f(uint[2] memory a, uint[2] memory b, uint[2] memory c) public pure { require(c[0] == 42); require(a[0] == 2); b[0] = 1; @@ -14,5 +14,5 @@ contract C } } // ---- -// Warning: (230-248): Assertion violation happens here -// Warning: (295-312): Assertion violation happens here +// Warning: (228-246): Assertion violation happens here +// Warning: (293-310): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol index fa0c5eae1384..45c12263be79 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_aliasing_storage_5.sol @@ -2,18 +2,25 @@ pragma experimental SMTChecker; contract C { - uint[2] b; + uint[2] b1; + uint[2] b2; function f(uint[2] storage a, uint[2] memory c) internal { - require(c[0] == 42); - require(a[0] == 2); - b[0] = 1; + c[0] = 42; + a[0] = 2; + b1[0] = 1; // Erasing knowledge about storage variables should not // erase knowledge about memory references. assert(c[0] == 42); - // Fails because b == a is possible. + // Fails because b1 == a is possible. assert(a[0] == 2); - assert(b[0] == 1); + assert(b1[0] == 1); + } + function g(bool x, uint[2] memory c) public { + if (x) f(b1, c); + else f(b2, c); } } // ---- -// Warning: (342-359): Assertion violation happens here +// Warning: (338-355): Assertion violation happens here +// Warning: (338-355): Assertion violation happens here +// Warning: (338-355): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol index a675c29e231c..7e31b10ae6a6 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_1.sol @@ -7,9 +7,9 @@ contract C mapping (uint => uint8)[2] severalMaps8; mapping (uint => uint)[2][2] severalMaps3d; function f(mapping (uint => uint) storage map) internal { - require(severalMaps[0][0] == 42); - require(severalMaps8[0][0] == 42); - require(severalMaps3d[0][0][0] == 42); + severalMaps[0][0] = 42; + severalMaps8[0][0] = 42; + severalMaps3d[0][0][0] = 42; map[0] = 2; // Should fail since map == severalMaps[0] is possible. assert(severalMaps[0][0] == 42); @@ -18,7 +18,12 @@ contract C // Should fail since map == severalMaps3d[0][0] is possible. assert(severalMaps3d[0][0][0] == 42); } + function g(uint x) public { + f(severalMaps[x]); + } } // ---- -// Warning: (455-486): Assertion violation happens here -// Warning: (669-705): Assertion violation happens here +// Warning: (425-456): Assertion violation happens here +// Warning: (639-675): Assertion violation happens here +// Warning: (425-456): Assertion violation happens here +// Warning: (639-675): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol index c9c96a0a7230..e2f597943df3 100644 --- a/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol +++ b/test/libsolidity/smtCheckerTests/types/array_static_mapping_aliasing_2.sol @@ -8,9 +8,9 @@ contract C mapping (uint => uint)[2][2] severalMaps3d; function f(mapping (uint => uint) storage map) internal { map[0] = 42; - require(severalMaps[0][0] == 42); - require(severalMaps8[0][0] == 42); - require(severalMaps3d[0][0][0] == 42); + severalMaps[0][0] = 42; + severalMaps8[0][0] = 42; + severalMaps3d[0][0][0] = 42; singleMap[0] = 2; // Should not fail since singleMap == severalMaps[0] is not possible. assert(severalMaps[0][0] == 42); @@ -21,6 +21,10 @@ contract C // Should fail since singleMap == map is possible. assert(map[0] == 42); } + function g(uint x) public { + f(severalMaps3d[x][0]); + } } // ---- -// Warning: (811-831): Assertion violation happens here +// Warning: (781-801): Assertion violation happens here +// Warning: (781-801): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/enum_in_library.sol b/test/libsolidity/smtCheckerTests/types/enum_in_library.sol index a1648c66e462..9c1c3caaa969 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_in_library.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_in_library.sol @@ -8,7 +8,7 @@ library L contract C { enum E { Left, Right } - function f(E _d) internal pure { + function f(E _d) public pure { _d = E.Left; assert(_d == E.Left); } diff --git a/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol b/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol index 2bd2afbda622..be1d40be4036 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_in_library_2.sol @@ -8,10 +8,10 @@ library L contract C { enum E { Left, Right } - function f(E _d) internal pure { + function f(E _d) public pure { _d = E.Right; assert(_d == E.Left); } } // ---- -// Warning: (161-181): Assertion violation happens here +// Warning: (159-179): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol b/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol index 47bdd0c66a0d..4821518fdc2b 100644 --- a/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol +++ b/test/libsolidity/smtCheckerTests/types/enum_in_struct.sol @@ -1,19 +1,20 @@ pragma experimental SMTChecker; +pragma experimental ABIEncoderV2; contract C { enum D { Left, Right } struct S { uint x; D d; } - function f(S memory s) internal pure { + function f(S memory s) public pure { s.d = D.Left; assert(s.d == D.Left); } } // ---- -// Warning: (109-119): Assertion checker does not yet support the type of this variable. -// Warning: (139-142): Assertion checker does not yet support this expression. -// Warning: (139-140): Assertion checker does not yet implement type struct C.S memory -// Warning: (139-151): Assertion checker does not yet implement such assignments. -// Warning: (162-165): Assertion checker does not yet support this expression. -// Warning: (162-163): Assertion checker does not yet implement type struct C.S memory -// Warning: (155-176): Assertion violation happens here +// Warning: (143-153): Assertion checker does not yet support the type of this variable. +// Warning: (171-174): Assertion checker does not yet support this expression. +// Warning: (171-172): Assertion checker does not yet implement type struct C.S memory +// Warning: (171-183): Assertion checker does not yet implement such assignments. +// Warning: (194-197): Assertion checker does not yet support this expression. +// Warning: (194-195): Assertion checker does not yet implement type struct C.S memory +// Warning: (187-208): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol new file mode 100644 index 000000000000..bb2513790959 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol @@ -0,0 +1,15 @@ +pragma experimental SMTChecker; + +contract C +{ + bytes32 x; + function f(bytes8 y) public view { + assert(x == g()); + assert(x != y); + } + function g() public view returns (bytes32) { + return x; + } +} +// ---- +// Warning: (116-130): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol index 39d096f5904c..8170d67e6200 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_1.sol @@ -5,8 +5,9 @@ contract C mapping (uint => uint) a; mapping (uint => uint) b; - function f() public { - require(a[1] == b[1]); + function f(uint x) public { + a[1] = x; + b[1] = x; a[1] = 2; mapping (uint => uint) storage c = a; assert(c[1] == 2); @@ -15,4 +16,4 @@ contract C } } // ---- -// Warning: (261-281): Assertion violation happens here +// Warning: (266-286): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol index 86af187ad75e..f31192b3a71e 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_aliasing_2.sol @@ -6,10 +6,10 @@ contract C mapping (uint => mapping (uint => uint)) maps; mapping (uint => mapping (uint => uint8)) maps8; function f(mapping (uint => uint) storage map1, mapping (uint => uint) storage map2) internal { - require(map1[0] == 2); - require(a[0] == 42); - require(maps[0][0] == 42); - require(maps8[0][0] == 42); + map1[0] = 2; + a[0] = 42; + maps[0][0] = 42; + maps8[0][0] = 42; map2[0] = 1; // Fails because map2 == map1 is possible. assert(map1[0] == 2); @@ -21,8 +21,21 @@ contract C assert(maps8[0][0] == 42); assert(map2[0] == 1); } + + function g(bool b, uint x, uint y) public { + if (b) + f(a, maps[y]); + else + f(maps[x], maps[y]); + } } // ---- -// Warning: (437-457): Assertion violation happens here -// Warning: (503-521): Assertion violation happens here -// Warning: (573-597): Assertion violation happens here +// Warning: (397-417): Assertion violation happens here +// Warning: (463-481): Assertion violation happens here +// Warning: (533-557): Assertion violation happens here +// Warning: (397-417): Assertion violation happens here +// Warning: (463-481): Assertion violation happens here +// Warning: (533-557): Assertion violation happens here +// Warning: (397-417): Assertion violation happens here +// Warning: (463-481): Assertion violation happens here +// Warning: (533-557): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol index 4a9291f89308..afb9a9ea0ac1 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_2.sol @@ -11,3 +11,4 @@ contract C { } // ---- // Warning: (147-166): Assertion violation happens here +// Warning: (170-190): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/tuple_function.sol b/test/libsolidity/smtCheckerTests/types/tuple_function.sol index 53b197395447..8103a02038c7 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_function.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_function.sol @@ -15,3 +15,4 @@ contract C } // ---- // Warning: (182-196): Assertion violation happens here +// Warning: (200-214): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol b/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol index 1e548403d0e9..e76db56d1245 100644 --- a/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol +++ b/test/libsolidity/smtCheckerTests/types/tuple_function_3.sol @@ -17,3 +17,4 @@ contract C } // ---- // Warning: (205-219): Assertion violation happens here +// Warning: (223-237): Assertion violation happens here diff --git a/test/libsolidity/smtCheckerTestsJSON/multi.json b/test/libsolidity/smtCheckerTestsJSON/multi.json index b125712fd310..b1be750736c5 100644 --- a/test/libsolidity/smtCheckerTestsJSON/multi.json +++ b/test/libsolidity/smtCheckerTestsJSON/multi.json @@ -3,7 +3,7 @@ { "smtlib2responses": { - "0x82fb8ee094f0f56b7a63a74177b54a1710d6fc531d426f288c18f36b76cf6a8b": "sat\n((|EVALEXPR_0| 1))\n", + "0x9c50514d749eabf3c13d97ad7d787e682dd99a114bad652b10a01b8c6ad6c1fb": "sat\n((|EVALEXPR_0| 1))\n", "0xb524e7c577188e2e36f0e67fead51269fa0f8b8fb41bff2d973dcf584d38cd1e": "sat\n((|EVALEXPR_0| 0))\n" } } From 89ce2dbfe92cf75baa53595c7f44a085977642e5 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 11 Mar 2020 17:55:14 +0100 Subject: [PATCH 023/165] The identifier `var` should be fine in Yul --- libyul/AsmParser.cpp | 2 ++ .../semanticTests/viaYul/mapping_string_key.sol | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 test/libsolidity/semanticTests/viaYul/mapping_string_key.sol diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 708e76339b50..758b11d92806 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -324,6 +324,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() case Token::Byte: case Token::Bool: case Token::Address: + case Token::Var: { YulString literal{currentLiteral()}; if (m_dialect.builtin(literal)) @@ -513,6 +514,7 @@ YulString Parser::expectAsmIdentifier() case Token::Address: case Token::Bool: case Token::Identifier: + case Token::Var: break; default: expectToken(Token::Identifier); diff --git a/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol b/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol new file mode 100644 index 000000000000..880522d60178 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/mapping_string_key.sol @@ -0,0 +1,10 @@ +contract C { + mapping (string => uint) map; + function set(string memory s) public { + map[s]; + } +} +// ==== +// compileViaYul: true +// ---- +// set(string): 0x20, 32, "01234567890123456789012345678901" -> From a86c5117132eb8308f37899713197d93c4b852a0 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Wed, 11 Mar 2020 00:32:01 +0100 Subject: [PATCH 024/165] Replaced "assert" with "if" (incorrect contract code is not supposed to trigger asserts). --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 6 +++--- libsolidity/ast/ASTUtils.cpp | 5 +++-- libsolidity/ast/ASTUtils.h | 5 +++-- libsolidity/codegen/ContractCompiler.cpp | 7 ++++++- .../inlineAssembly/const_from_non_const.sol | 12 ++++++++++++ .../syntaxTests/inlineAssembly/const_from_this.sol | 12 ++++++++++++ 7 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol diff --git a/Changelog.md b/Changelog.md index a5d4aab67848..492b0c7543a1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Compiler Features: Bugfixes: + * Inline Assembly: Fix internal error when accessing incorrect constant variables. ### 0.6.4 (2020-03-10) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 5cf003bed5b9..a9b2b5b9fb8c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -643,14 +643,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(var->type(), "Expected variable type!"); if (var->isConstant()) { - var = rootVariableDeclaration(*var); + var = rootConstVariableDeclaration(*var); - if (!var->value()) + if (var && !var->value()) { m_errorReporter.typeError(_identifier.location, "Constant has no value."); return size_t(-1); } - else if (!type(*var)->isValueType() || ( + else if (!var || !type(*var)->isValueType() || ( dynamic_cast(var->value().get()) == nullptr && type(*var->value())->category() != Type::Category::RationalNumber )) diff --git a/libsolidity/ast/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp index d903a1b4b888..483b75301ac3 100644 --- a/libsolidity/ast/ASTUtils.cpp +++ b/libsolidity/ast/ASTUtils.cpp @@ -21,7 +21,7 @@ namespace solidity::frontend { -VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _varDecl) +VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl) { solAssert(_varDecl.isConstant(), "Constant variable expected"); @@ -30,7 +30,8 @@ VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _v while ((identifier = dynamic_cast(rootDecl->value().get()))) { auto referencedVarDecl = dynamic_cast(identifier->annotation().referencedDeclaration); - solAssert(referencedVarDecl && referencedVarDecl->isConstant(), "Identifier is not referencing a variable declaration"); + if (!referencedVarDecl || !referencedVarDecl->isConstant()) + return nullptr; rootDecl = referencedVarDecl; } return rootDecl; diff --git a/libsolidity/ast/ASTUtils.h b/libsolidity/ast/ASTUtils.h index 7624080a9c65..af77b60f11a6 100644 --- a/libsolidity/ast/ASTUtils.h +++ b/libsolidity/ast/ASTUtils.h @@ -22,8 +22,9 @@ namespace solidity::frontend class VariableDeclaration; -/// Find the topmost referenced variable declaration when the given variable +/// Find the topmost referenced constant variable declaration when the given variable /// declaration value is an identifier. Works only for constant variable declarations. -VariableDeclaration const* rootVariableDeclaration(VariableDeclaration const& _varDecl); +/// Returns nullptr if an identifier in the chain is not referencing a constant variable declaration. +VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl); } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 8b9061af3d2a..21886faaf228 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -682,7 +682,12 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { if (variable->isConstant()) { - variable = rootVariableDeclaration(*variable); + variable = rootConstVariableDeclaration(*variable); + // If rootConstVariableDeclaration fails and returns nullptr, + // it should have failed in TypeChecker already, causing a compilation error. + // In such case we should not get here. + solAssert(variable, ""); + u256 value; if (variable->value()->annotation().type->category() == Type::Category::RationalNumber) { diff --git a/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol b/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol new file mode 100644 index 000000000000..fbd5ab6ee0a4 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/const_from_non_const.sol @@ -0,0 +1,12 @@ +contract C { + bool nc = false; + bool constant c = nc; + function f() public { + assembly { + let t := c + } + } +} +// ---- +// TypeError: (52-54): Initial value for constant variable has to be compile-time constant. +// TypeError: (112-113): Only direct number constants and references to such constants are supported by inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol b/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol new file mode 100644 index 000000000000..563d47851a9d --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/const_from_this.sol @@ -0,0 +1,12 @@ +contract C { + bool constant c = this; + function f() public { + assembly { + let t := c + } + } +} +// ---- +// TypeError: (33-37): Type contract C is not implicitly convertible to expected type bool. +// TypeError: (33-37): Initial value for constant variable has to be compile-time constant. +// TypeError: (95-96): Only direct number constants and references to such constants are supported by inline assembly. From fa148f2483fac9315dd5452a02707bbfffe8014f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 27 Feb 2020 16:13:55 +0100 Subject: [PATCH 025/165] Parsing of immutable state variable. --- libsolidity/analysis/ReferencesResolver.cpp | 4 +++- libsolidity/analysis/TypeChecker.cpp | 9 +++++++++ libsolidity/ast/AST.cpp | 2 -- libsolidity/ast/AST.h | 1 + libsolidity/ast/Types.cpp | 2 +- libsolidity/codegen/ContractCompiler.cpp | 5 ++++- libsolidity/codegen/ExpressionCompiler.cpp | 10 ++++++---- libsolidity/codegen/ir/IRGenerator.cpp | 3 ++- .../codegen/ir/IRGeneratorForStatements.cpp | 2 ++ libsolidity/parsing/Parser.cpp | 14 ++++++++++++-- .../syntaxTests/immutable/as_function_param.sol | 5 +++++ .../libsolidity/syntaxTests/immutable/assembly.sol | 11 +++++++++++ .../syntaxTests/immutable/double_specifier.sol | 7 +++++++ test/libsolidity/syntaxTests/immutable/getter.sol | 5 +++++ .../syntaxTests/immutable/immutable_basic.sol | 3 +++ .../syntaxTests/immutable/non-value_type.sol | 5 +++++ .../syntaxTests/viewPureChecker/immutable.sol | 8 ++++++++ 17 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 test/libsolidity/syntaxTests/immutable/as_function_param.sol create mode 100644 test/libsolidity/syntaxTests/immutable/assembly.sol create mode 100644 test/libsolidity/syntaxTests/immutable/double_specifier.sol create mode 100644 test/libsolidity/syntaxTests/immutable/getter.sol create mode 100644 test/libsolidity/syntaxTests/immutable/immutable_basic.sol create mode 100644 test/libsolidity/syntaxTests/immutable/non-value_type.sol create mode 100644 test/libsolidity/syntaxTests/viewPureChecker/immutable.sol diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 6867f049c50c..8ea07f1829cb 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -328,6 +328,8 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) if (_variable.isConstant() && !_variable.isStateVariable()) m_errorReporter.declarationError(_variable.location(), "The \"constant\" keyword can only be used for state variables."); + if (_variable.immutable() && !_variable.isStateVariable()) + m_errorReporter.declarationError(_variable.location(), "The \"immutable\" keyword can only be used for state variables."); if (!_variable.typeName()) { @@ -394,7 +396,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) else if (_variable.isStateVariable()) { solAssert(varLoc == Location::Unspecified, ""); - typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage; + typeLoc = (_variable.isConstant() || _variable.immutable()) ? DataLocation::Memory : DataLocation::Storage; } else if ( dynamic_cast(_variable.scope()) || diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index a9b2b5b9fb8c..1345fbf90008 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -480,6 +480,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) "Initial value for constant variable has to be compile-time constant." ); } + else if (_variable.immutable()) + if (!_variable.type()->isValueType()) + m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type."); + if (!_variable.isStateVariable()) { if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData)) @@ -641,6 +645,11 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (auto var = dynamic_cast(declaration)) { solAssert(var->type(), "Expected variable type!"); + if (var->immutable()) + { + m_errorReporter.typeError(_identifier.location, "Assembly access to immutable variables is not supported."); + return size_t(-1); + } if (var->isConstant()) { var = rootConstVariableDeclaration(*var); diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 6b03c7b586e9..a76e6e274171 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -508,8 +508,6 @@ set VariableDeclaration::allowedDataLocations() c if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter()) return set{ Location::Unspecified }; - else if (isStateVariable() && isConstant()) - return set{ Location::Memory }; else if (isExternalCallableParameter()) { set locations{ Location::CallData }; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index adb957cfec5b..052970bc862b 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -879,6 +879,7 @@ class VariableDeclaration: public Declaration bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } bool isConstant() const { return m_constantness == Constantness::Constant; } + bool immutable() const { return m_constantness == Constantness::Immutable; } ASTPointer const& overrides() const { return m_overrides; } Location referenceLocation() const { return m_location; } /// @returns a set of allowed storage locations for the variable. diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 454ca8f3cb6f..d760e08102e7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1988,7 +1988,7 @@ vector> ContractType::stateVar vector variables; for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts)) for (VariableDeclaration const* variable: contract->stateVariables()) - if (!variable->isConstant()) + if (!(variable->isConstant() || variable->immutable())) variables.push_back(variable); TypePointers types; for (auto variable: variables) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 21886faaf228..6fffbd5b50ab 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -525,7 +525,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr { solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library."); for (VariableDeclaration const* variable: _contract.stateVariables()) - if (variable->value() && !variable->isConstant()) + if (variable->value() && !variable->isConstant() && !variable->immutable()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable); } @@ -541,6 +541,8 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration) if (_variableDeclaration.isConstant()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendConstStateVariableAccessor(_variableDeclaration); + else if (_variableDeclaration.immutable()) + solUnimplementedAssert(false, ""); else ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendStateVariableAccessor(_variableDeclaration); @@ -680,6 +682,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (auto variable = dynamic_cast(decl)) { + solAssert(!variable->immutable(), ""); if (variable->isConstant()) { variable = rootConstVariableDeclaration(*variable); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 0fc24d919e68..2b6285c0afa2 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -88,7 +88,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), ""); CompilerContext::LocationSetter locationSetter(m_context, _varDecl); FunctionType accessorType(_varDecl); @@ -2438,10 +2438,12 @@ void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Expression const& _expression) { - if (!_variable.isConstant()) - setLValueFromDeclaration(_variable, _expression); - else + if (_variable.isConstant()) acceptAndConvert(*_variable.value(), *_variable.annotation().type); + else if (_variable.immutable()) + solUnimplemented(""); + else + setLValueFromDeclaration(_variable, _expression); } void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 8da57605548d..9c7d9c8ace74 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -157,6 +157,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) Type const* type = _varDecl.annotation().type; solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.immutable(), ""); solAssert(_varDecl.isStateVariable(), ""); if (auto const* mappingType = dynamic_cast(type)) @@ -249,7 +250,7 @@ string IRGenerator::constructorCode(ContractDefinition const& _contract) IRGeneratorForStatements generator{m_context, m_utils}; for (VariableDeclaration const* variable: contract->stateVariables()) - if (!variable->isConstant()) + if (!variable->isConstant() && !variable->immutable()) generator.initializeStateVar(*variable); out << generator.code(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e370acd7c82e..5a413a4494f5 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -140,6 +140,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va { solAssert(m_context.isStateVariable(_varDecl), "Must be a state variable."); solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.immutable(), ""); if (_varDecl.value()) { _varDecl.value()->accept(*this); @@ -1123,6 +1124,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) // If the value is visited twice, `defineExpression` is called twice on // the same expression. solUnimplementedAssert(!varDecl->isConstant(), ""); + solUnimplementedAssert(!varDecl->immutable(), ""); if (m_context.isLocalVariable(*varDecl)) setLValue(_identifier, IRLValue{ *varDecl->annotation().type, diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index edf43377f67c..2f23c8c22dd0 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -730,8 +730,18 @@ ASTPointer Parser::parseVariableDeclaration( { if (_options.allowIndexed && token == Token::Indexed) isIndexed = true; - else if (token == Token::Constant) - constantness = VariableDeclaration::Constantness::Constant; + else if (token == Token::Constant || token == Token::Immutable) + { + if (constantness != VariableDeclaration::Constantness::Mutable) + parserError( + string("Constantness already set to ") + + (constantness == VariableDeclaration::Constantness::Constant ? "\"constant\"" : "\"immutable\"") + ); + else if (token == Token::Constant) + constantness = VariableDeclaration::Constantness::Constant; + else if (token == Token::Immutable) + constantness = VariableDeclaration::Constantness::Immutable; + } else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Unspecified) diff --git a/test/libsolidity/syntaxTests/immutable/as_function_param.sol b/test/libsolidity/syntaxTests/immutable/as_function_param.sol new file mode 100644 index 000000000000..3636b0aef679 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/as_function_param.sol @@ -0,0 +1,5 @@ +contract C { + function f(uint immutable) public pure {} +} +// ---- +// DeclarationError: (28-42): The "immutable" keyword can only be used for state variables. diff --git a/test/libsolidity/syntaxTests/immutable/assembly.sol b/test/libsolidity/syntaxTests/immutable/assembly.sol new file mode 100644 index 000000000000..7b98b67c66df --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/assembly.sol @@ -0,0 +1,11 @@ +contract C { + uint immutable x; + function f() public view { + uint t; + assembly { + t := x + } + } +} +// ---- +// TypeError: (118-119): Assembly access to immutable variables is not supported. diff --git a/test/libsolidity/syntaxTests/immutable/double_specifier.sol b/test/libsolidity/syntaxTests/immutable/double_specifier.sol new file mode 100644 index 000000000000..39f0f1e76e64 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/double_specifier.sol @@ -0,0 +1,7 @@ +contract C { + uint immutable immutable x; + uint immutable constant x; +} +// ---- +// ParserError: (32-41): Constantness already set to "immutable" +// ParserError: (64-72): Constantness already set to "immutable" diff --git a/test/libsolidity/syntaxTests/immutable/getter.sol b/test/libsolidity/syntaxTests/immutable/getter.sol new file mode 100644 index 000000000000..7740f86430f9 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/getter.sol @@ -0,0 +1,5 @@ +contract C { + uint immutable public x; +} +// ---- +// UnimplementedFeatureError: NONE diff --git a/test/libsolidity/syntaxTests/immutable/immutable_basic.sol b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol new file mode 100644 index 000000000000..b4960f25b9a0 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol @@ -0,0 +1,3 @@ +contract C { + uint immutable x; +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/immutable/non-value_type.sol b/test/libsolidity/syntaxTests/immutable/non-value_type.sol new file mode 100644 index 000000000000..67398ce20455 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/non-value_type.sol @@ -0,0 +1,5 @@ +contract C { + uint[] immutable x; +} +// ---- +// TypeError: (17-35): Immutable variables cannot have a non-value type. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol new file mode 100644 index 000000000000..1c0e7a46f0ef --- /dev/null +++ b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol @@ -0,0 +1,8 @@ +contract B { + uint immutable x; + function f() public pure returns (uint) { + return x; + } +} +// ---- +// TypeError: (96-97): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". From 9d67edb1637dfe7e1b8a197c0e4b60224a319270 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 10 Mar 2020 21:07:11 -0500 Subject: [PATCH 026/165] Add --show-metadata to enable metadata output. --- test/Common.cpp | 3 ++- test/Common.h | 1 + test/libsolidity/SolidityExecutionFramework.cpp | 10 ++++++---- test/libsolidity/SolidityExecutionFramework.h | 5 +++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index 709840bbcef9..0ed7c9881854 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -96,7 +96,8 @@ CommonOptions::CommonOptions(std::string _caption): ("optimize", po::bool_switch(&optimize), "enables optimization") ("optimize-yul", po::bool_switch(&optimizeYul), "enables Yul optimization") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") - ("show-messages", po::bool_switch(&showMessages), "enables message output"); + ("show-messages", po::bool_switch(&showMessages), "enables message output") + ("show-metadata", po::bool_switch(&showMetadata), "enables metadata output"); } void CommonOptions::validate() const diff --git a/test/Common.h b/test/Common.h index 63437da13d9f..a65c95539328 100644 --- a/test/Common.h +++ b/test/Common.h @@ -50,6 +50,7 @@ struct CommonOptions: boost::noncopyable bool disableSMT = false; bool useABIEncoderV2 = false; bool showMessages = false; + bool showMetadata = false; langutil::EVMVersion evmVersion() const; diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp index dcfb3e6bfbc3..0afe95c6d246 100644 --- a/test/libsolidity/SolidityExecutionFramework.cpp +++ b/test/libsolidity/SolidityExecutionFramework.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -60,6 +61,7 @@ bytes SolidityExecutionFramework::compileContract( formatter.printErrorInformation(*error); BOOST_ERROR("Compiling contract failed"); } + std::string contractName(_contractName.empty() ? m_compiler.lastContractName() : _contractName); evmasm::LinkerObject obj; if (m_compileViaYul) { @@ -70,9 +72,7 @@ bytes SolidityExecutionFramework::compileContract( // get code that does not exhaust the stack. OptimiserSettings::full() ); - if (!asmStack.parseAndAnalyze("", m_compiler.yulIROptimized( - _contractName.empty() ? m_compiler.lastContractName() : _contractName - ))) + if (!asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName))) { langutil::SourceReferenceFormatter formatter(std::cerr); @@ -84,7 +84,9 @@ bytes SolidityExecutionFramework::compileContract( obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode); } else - obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName); + obj = m_compiler.object(contractName); BOOST_REQUIRE(obj.linkReferences.empty()); + if (m_showMetadata) + cout << "metadata: " << m_compiler.metadata(contractName) << endl; return obj.bytecode; } diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index dfcf4a46b705..aaa17525f401 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -41,9 +41,9 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework { public: - SolidityExecutionFramework() {} + SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion): - ExecutionFramework(_evmVersion) + ExecutionFramework(_evmVersion), m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {} virtual bytes const& compileAndRunWithoutCheck( @@ -68,6 +68,7 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework protected: solidity::frontend::CompilerStack m_compiler; bool m_compileViaYul = false; + bool m_showMetadata = false; RevertStrings m_revertStrings = RevertStrings::Default; }; From 3e3887dc9aaa50995738b4d7b1fce42d2c8b464c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 2 Mar 2020 01:05:42 +0100 Subject: [PATCH 027/165] [yul-phaser] main: Add missing underscores to parameter names --- tools/yulPhaser/main.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 4af735d0bb12..557a1f74e662 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -45,31 +45,31 @@ enum class Algorithm GEWEP }; -istream& operator>>(istream& inputStream, Algorithm& algorithm) +istream& operator>>(istream& _inputStream, Algorithm& _algorithm) { string value; - inputStream >> value; + _inputStream >> value; if (value == "random") - algorithm = Algorithm::Random; + _algorithm = Algorithm::Random; else if (value == "GEWEP") - algorithm = Algorithm::GEWEP; + _algorithm = Algorithm::GEWEP; else - inputStream.setstate(ios_base::failbit); + _inputStream.setstate(ios_base::failbit); - return inputStream; + return _inputStream; } -ostream& operator<<(ostream& outputStream, Algorithm algorithm) +ostream& operator<<(ostream& _outputStream, Algorithm _algorithm) { - if (algorithm == Algorithm::Random) - outputStream << "random"; - else if (algorithm == Algorithm::GEWEP) - outputStream << "GEWEP"; + if (_algorithm == Algorithm::Random) + _outputStream << "random"; + else if (_algorithm == Algorithm::GEWEP) + _outputStream << "GEWEP"; else - outputStream.setstate(ios_base::failbit); + _outputStream.setstate(ios_base::failbit); - return outputStream; + return _outputStream; } namespace @@ -82,11 +82,11 @@ struct CommandLineParsingResult }; -void initialiseRNG(po::variables_map const& arguments) +void initialiseRNG(po::variables_map const& _arguments) { uint32_t seed; - if (arguments.count("seed") > 0) - seed = arguments["seed"].as(); + if (_arguments.count("seed") > 0) + seed = _arguments["seed"].as(); else seed = SimulationRNG::generateSeed(); @@ -153,7 +153,7 @@ void runAlgorithm(string const& _sourcePath, Algorithm _algorithm) } } -CommandLineParsingResult parseCommandLine(int argc, char** argv) +CommandLineParsingResult parseCommandLine(int _argc, char** _argv) { po::options_description description( "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" @@ -187,7 +187,7 @@ CommandLineParsingResult parseCommandLine(int argc, char** argv) try { - po::command_line_parser parser(argc, argv); + po::command_line_parser parser(_argc, _argv); parser.options(description).positional(positionalDescription); po::store(parser.run(), arguments); } From 0c1b88508efa6a1b7ac24988eb567e6bea94277f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 15:55:02 +0100 Subject: [PATCH 028/165] [yul-phaser] Refactor the code from main into a Phaser class --- tools/CMakeLists.txt | 2 + tools/yulPhaser/Phaser.cpp | 218 +++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Phaser.h | 64 +++++++++++ tools/yulPhaser/main.cpp | 213 +----------------------------------- 4 files changed, 288 insertions(+), 209 deletions(-) create mode 100644 tools/yulPhaser/Phaser.cpp create mode 100644 tools/yulPhaser/Phaser.h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 4791087b52f8..f281439bf1b3 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -15,6 +15,8 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}") add_executable(yul-phaser yulPhaser/main.cpp + yulPhaser/Phaser.h + yulPhaser/Phaser.cpp yulPhaser/GeneticAlgorithms.h yulPhaser/GeneticAlgorithms.cpp yulPhaser/Population.h diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp new file mode 100644 index 000000000000..a1a955d57c28 --- /dev/null +++ b/tools/yulPhaser/Phaser.cpp @@ -0,0 +1,218 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::langutil; +using namespace solidity::util; +using namespace solidity::phaser; + +namespace po = boost::program_options; + +istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) +{ + string value; + _inputStream >> value; + + if (value == "random") + _algorithm = Algorithm::Random; + else if (value == "GEWEP") + _algorithm = Algorithm::GEWEP; + else + _inputStream.setstate(ios_base::failbit); + + return _inputStream; +} + +ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) +{ + if (_algorithm == Algorithm::Random) + _outputStream << "random"; + else if (_algorithm == Algorithm::GEWEP) + _outputStream << "GEWEP"; + else + _outputStream.setstate(ios_base::failbit); + + return _outputStream; +} + +namespace +{ + +CharStream loadSource(string const& _sourcePath) +{ + assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); + + string sourceCode = readFileAsString(_sourcePath); + return CharStream(sourceCode, _sourcePath); +} + +} + +int Phaser::main(int _argc, char** _argv) +{ + CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv); + if (parsingResult.exitCode != 0) + return parsingResult.exitCode; + + initialiseRNG(parsingResult.arguments); + + runAlgorithm( + parsingResult.arguments["input-file"].as(), + parsingResult.arguments["algorithm"].as() + ); + return 0; +} + +Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _argv) +{ + po::options_description description( + "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" + "\n" + "Usage: yul-phaser [options] \n" + "Reads as Yul code and tries to find the best order in which to run optimisation" + " phases using a genetic algorithm.\n" + "Example:\n" + "yul-phaser program.yul\n" + "\n" + "Allowed options", + po::options_description::m_default_line_length, + po::options_description::m_default_line_length - 23 + ); + + description.add_options() + ("help", "Show help message and exit.") + ("input-file", po::value()->required(), "Input file") + ("seed", po::value(), "Seed for the random number generator") + ( + "algorithm", + po::value()->default_value(Algorithm::GEWEP), + "Algorithm" + ) + ; + + po::positional_options_description positionalDescription; + po::variables_map arguments; + positionalDescription.add("input-file", 1); + po::notify(arguments); + + try + { + po::command_line_parser parser(_argc, _argv); + parser.options(description).positional(positionalDescription); + po::store(parser.run(), arguments); + } + catch (po::error const & _exception) + { + cerr << _exception.what() << endl; + return {1, move(arguments)}; + } + + if (arguments.count("help") > 0) + { + cout << description << endl; + return {2, move(arguments)}; + } + + if (arguments.count("input-file") == 0) + { + cerr << "Missing argument: input-file." << endl; + return {1, move(arguments)}; + } + + return {0, arguments}; +} + +void Phaser::initialiseRNG(po::variables_map const& _arguments) +{ + uint32_t seed; + if (_arguments.count("seed") > 0) + seed = _arguments["seed"].as(); + else + seed = SimulationRNG::generateSeed(); + + SimulationRNG::reset(seed); + cout << "Random seed: " << seed << endl; +} + +void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm) +{ + constexpr size_t populationSize = 20; + constexpr size_t minChromosomeLength = 12; + constexpr size_t maxChromosomeLength = 30; + + CharStream sourceCode = loadSource(_sourcePath); + shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5); + auto population = Population::makeRandom( + fitnessMetric, + populationSize, + minChromosomeLength, + maxChromosomeLength + ); + + switch (_algorithm) + { + case Algorithm::Random: + { + RandomAlgorithm( + population, + cout, + { + /* elitePoolSize = */ 1.0 / populationSize, + /* minChromosomeLength = */ minChromosomeLength, + /* maxChromosomeLength = */ maxChromosomeLength, + } + ).run(); + + break; + } + case Algorithm::GEWEP: + { + GenerationalElitistWithExclusivePools( + population, + cout, + { + /* mutationPoolSize = */ 0.25, + /* crossoverPoolSize = */ 0.25, + /* randomisationChance = */ 0.9, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, + /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, + } + ).run(); + + break; + } + } +} diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h new file mode 100644 index 000000000000..65a82eba49e1 --- /dev/null +++ b/tools/yulPhaser/Phaser.h @@ -0,0 +1,64 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains the main class that controls yul-phaser based on command-line parameters. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace solidity::phaser +{ + +enum class Algorithm +{ + Random, + GEWEP, +}; + +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); + +/** + * Main class that controls yul-phaser based on command-line parameters. The class is responsible + * for command-line parsing, initialisation of global objects (like the random number generator), + * creating instances of main components and running the genetic algorithm. + */ +class Phaser +{ +public: + static int main(int argc, char** argv); + +private: + struct CommandLineParsingResult + { + int exitCode; + boost::program_options::variables_map arguments; + }; + + static CommandLineParsingResult parseCommandLine(int _argc, char** _argv); + static void initialiseRNG(boost::program_options::variables_map const& _arguments); + + static void runAlgorithm(std::string const& _sourcePath, Algorithm _algorithm); +}; + +} diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 557a1f74e662..eecaf6d3c8fc 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -16,224 +16,19 @@ */ #include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include +#include #include -#include - -using namespace std; -using namespace solidity::langutil; -using namespace solidity::phaser; -using namespace solidity::util; - -namespace po = boost::program_options; - -enum class Algorithm -{ - Random, - GEWEP -}; - -istream& operator>>(istream& _inputStream, Algorithm& _algorithm) -{ - string value; - _inputStream >> value; - - if (value == "random") - _algorithm = Algorithm::Random; - else if (value == "GEWEP") - _algorithm = Algorithm::GEWEP; - else - _inputStream.setstate(ios_base::failbit); - - return _inputStream; -} - -ostream& operator<<(ostream& _outputStream, Algorithm _algorithm) -{ - if (_algorithm == Algorithm::Random) - _outputStream << "random"; - else if (_algorithm == Algorithm::GEWEP) - _outputStream << "GEWEP"; - else - _outputStream.setstate(ios_base::failbit); - - return _outputStream; -} - -namespace -{ - -struct CommandLineParsingResult -{ - int exitCode; - po::variables_map arguments; -}; - - -void initialiseRNG(po::variables_map const& _arguments) -{ - uint32_t seed; - if (_arguments.count("seed") > 0) - seed = _arguments["seed"].as(); - else - seed = SimulationRNG::generateSeed(); - - SimulationRNG::reset(seed); - cout << "Random seed: " << seed << endl; -} - -CharStream loadSource(string const& _sourcePath) -{ - assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); - - string sourceCode = readFileAsString(_sourcePath); - return CharStream(sourceCode, _sourcePath); -} - -void runAlgorithm(string const& _sourcePath, Algorithm _algorithm) -{ - constexpr size_t populationSize = 20; - constexpr size_t minChromosomeLength = 12; - constexpr size_t maxChromosomeLength = 30; - - CharStream sourceCode = loadSource(_sourcePath); - shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5); - auto population = Population::makeRandom( - fitnessMetric, - populationSize, - minChromosomeLength, - maxChromosomeLength - ); - - switch (_algorithm) - { - case Algorithm::Random: - { - RandomAlgorithm( - population, - cout, - { - /* elitePoolSize = */ 1.0 / populationSize, - /* minChromosomeLength = */ minChromosomeLength, - /* maxChromosomeLength = */ maxChromosomeLength, - } - ).run(); - - break; - } - case Algorithm::GEWEP: - { - GenerationalElitistWithExclusivePools( - population, - cout, - { - /* mutationPoolSize = */ 0.25, - /* crossoverPoolSize = */ 0.25, - /* randomisationChance = */ 0.9, - /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, - /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, - } - ).run(); - - break; - } - } -} - -CommandLineParsingResult parseCommandLine(int _argc, char** _argv) -{ - po::options_description description( - "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" - "\n" - "Usage: yul-phaser [options] \n" - "Reads as Yul code and tries to find the best order in which to run optimisation" - " phases using a genetic algorithm.\n" - "Example:\n" - "yul-phaser program.yul\n" - "\n" - "Allowed options", - po::options_description::m_default_line_length, - po::options_description::m_default_line_length - 23 - ); - - description.add_options() - ("help", "Show help message and exit.") - ("input-file", po::value()->required(), "Input file") - ("seed", po::value(), "Seed for the random number generator") - ( - "algorithm", - po::value()->default_value(Algorithm::GEWEP), - "Algorithm" - ) - ; - - po::positional_options_description positionalDescription; - po::variables_map arguments; - positionalDescription.add("input-file", 1); - po::notify(arguments); - - try - { - po::command_line_parser parser(_argc, _argv); - parser.options(description).positional(positionalDescription); - po::store(parser.run(), arguments); - } - catch (po::error const & _exception) - { - cerr << _exception.what() << endl; - return {1, move(arguments)}; - } - - if (arguments.count("help") > 0) - { - cout << description << endl; - return {2, move(arguments)}; - } - - if (arguments.count("input-file") == 0) - { - cerr << "Missing argument: input-file." << endl; - return {1, move(arguments)}; - } - - return {0, arguments}; -} - -} int main(int argc, char** argv) { - CommandLineParsingResult parsingResult = parseCommandLine(argc, argv); - if (parsingResult.exitCode != 0) - return parsingResult.exitCode; - - initialiseRNG(parsingResult.arguments); - try { - runAlgorithm( - parsingResult.arguments["input-file"].as(), - parsingResult.arguments["algorithm"].as() - ); + return solidity::phaser::Phaser::main(argc, argv); } - catch (InvalidProgram const& _exception) + catch (solidity::phaser::InvalidProgram const& exception) { - cerr << "ERROR: " << _exception.what() << endl; + std::cerr << "ERROR: " << exception.what() << std::endl; return 1; } - - return 0; } From b8244f6a431ff39439e2cf2996a66d4cac9c1059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 16:10:07 +0100 Subject: [PATCH 029/165] [yul-phaser] Extract the code that controls execution of algorithm rounds from GeneticAlgorithm into AlgorithmRunner --- test/CMakeLists.txt | 2 + test/yulPhaser/AlgorithmRunner.cpp | 93 +++++++++++++++++++++ test/yulPhaser/GeneticAlgorithms.cpp | 112 ++++++++------------------ tools/CMakeLists.txt | 2 + tools/yulPhaser/AlgorithmRunner.cpp | 32 ++++++++ tools/yulPhaser/AlgorithmRunner.h | 58 +++++++++++++ tools/yulPhaser/GeneticAlgorithms.cpp | 31 +++---- tools/yulPhaser/GeneticAlgorithms.h | 46 ++--------- tools/yulPhaser/Phaser.cpp | 40 ++++----- tools/yulPhaser/Phaser.h | 2 +- 10 files changed, 255 insertions(+), 163 deletions(-) create mode 100644 test/yulPhaser/AlgorithmRunner.cpp create mode 100644 tools/yulPhaser/AlgorithmRunner.cpp create mode 100644 tools/yulPhaser/AlgorithmRunner.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index da6995e384e2..d78711634759 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -144,6 +144,7 @@ set(yul_phaser_sources yulPhaser/CommonTest.cpp yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp + yulPhaser/AlgorithmRunner.cpp yulPhaser/GeneticAlgorithms.cpp yulPhaser/Mutations.cpp yulPhaser/PairSelections.cpp @@ -155,6 +156,7 @@ set(yul_phaser_sources # FIXME: yul-phaser is not a library so I can't just add it to target_link_libraries(). # My current workaround is just to include its source files here but this introduces # unnecessary duplication. Create a library or find a way to reuse the list in both places. + ../tools/yulPhaser/AlgorithmRunner.cpp ../tools/yulPhaser/Chromosome.cpp ../tools/yulPhaser/FitnessMetrics.cpp ../tools/yulPhaser/GeneticAlgorithms.cpp diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp new file mode 100644 index 000000000000..16a4dd8936c0 --- /dev/null +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -0,0 +1,93 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace boost::unit_test::framework; +using namespace boost::test_tools; +using namespace solidity::util; + +namespace solidity::phaser::test +{ + +class DummyAlgorithm: public GeneticAlgorithm +{ +public: + using GeneticAlgorithm::GeneticAlgorithm; + Population runNextRound(Population _population) override + { + ++m_currentRound; + return _population; + } + + size_t m_currentRound = 0; +}; + +class AlgorithmRunnerFixture +{ +protected: + shared_ptr m_fitnessMetric = make_shared(); + output_test_stream m_output; +}; + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) + +BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRunnerFixture) +{ + AlgorithmRunner runner(Population(m_fitnessMetric), m_output); + DummyAlgorithm algorithm; + + BOOST_TEST(algorithm.m_currentRound == 0); + runner.run(algorithm, 10); + BOOST_TEST(algorithm.m_currentRound == 10); + runner.run(algorithm, 3); + BOOST_TEST(algorithm.m_currentRound == 13); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixture) +{ + // run() is allowed to print more but should at least print the first one + + AlgorithmRunner runner( + // NOTE: Chromosomes chosen so that they're not substrings of each other and are not + // words likely to appear in the output in normal circumstances. + Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), + m_output + ); + + DummyAlgorithm algorithm; + + BOOST_TEST(m_output.is_empty()); + runner.run(algorithm, 1); + BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 1); + runner.run(algorithm, 3); + BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index 0d32e9c1d369..13a3116692d0 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -20,14 +20,10 @@ #include #include #include -#include - -#include #include #include -#include #include #include @@ -35,102 +31,58 @@ using namespace std; using namespace boost::unit_test::framework; using namespace boost::test_tools; -using namespace solidity::langutil; -using namespace solidity::util; namespace solidity::phaser::test { -class DummyAlgorithm: public GeneticAlgorithm -{ -public: - using GeneticAlgorithm::GeneticAlgorithm; - void runNextRound() override { ++m_currentRound; } - - size_t m_currentRound = 0; -}; - class GeneticAlgorithmFixture { protected: shared_ptr m_fitnessMetric = make_shared(); - output_test_stream m_output; }; BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(GeneticAlgorithmsTest) -BOOST_AUTO_TEST_SUITE(GeneticAlgorithmTest) - -BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, GeneticAlgorithmFixture) -{ - DummyAlgorithm algorithm(Population(m_fitnessMetric), m_output); - - BOOST_TEST(algorithm.m_currentRound == 0); - algorithm.run(10); - BOOST_TEST(algorithm.m_currentRound == 10); - algorithm.run(3); - BOOST_TEST(algorithm.m_currentRound == 13); -} - -BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, GeneticAlgorithmFixture) -{ - // run() is allowed to print more but should at least print the first one - - DummyAlgorithm algorithm( - // NOTE: Chromosomes chosen so that they're not substrings of each other and are not - // words likely to appear in the output in normal circumstances. - Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), - m_output - ); - - BOOST_TEST(m_output.is_empty()); - algorithm.run(1); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 1); - algorithm.run(3); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(algorithm.population().individuals()[0].chromosome)) == 4); -} - -BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(RandomAlgorithmTest) BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_randomise_rest_of_population, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.5, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.5, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{1, 1, 1, 1, 3, 3, 3, 3})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{1, 1, 1, 1, 3, 3, 3, 3})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individuals, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.5, 7, 7}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.5, 7, 7}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 7, 7, 7, 7})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 7, 7, 7, 7})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_replace_all_chromosomes_if_zero_size_elite, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {0.0, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({0.0, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{1, 1, 1, 1, 1, 1, 1, 1})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{1, 1, 1, 1, 1, 1, 1, 1})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_any_chromosomes_if_whole_population_is_the_elite, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 4, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); - RandomAlgorithm algorithm(population, m_output, {1.0, 1, 1}); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + RandomAlgorithm algorithm({1.0, 1, 1}); - algorithm.runNextRound(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 5, 5, 5, 5})); + Population newPopulation = algorithm.runNextRound(population); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 5, 5, 5, 5})); } BOOST_AUTO_TEST_SUITE_END() @@ -139,6 +91,7 @@ BOOST_AUTO_TEST_SUITE(GenerationalElitistWithExclusivePoolsTest) BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_regenerate_rest_of_population, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + assert((chromosomeLengths(population) == vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); GenerationalElitistWithExclusivePools::Options options = { /* mutationPoolSize = */ 0.2, @@ -148,17 +101,17 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_preserve_elite_and_regenerate_rest_o /* percentGenesToRandomise = */ 0.0, /* percentGenesToAddOrDelete = */ 1.0, }; - GenerationalElitistWithExclusivePools algorithm(population, m_output, options); - assert((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + GenerationalElitistWithExclusivePools algorithm(options); - algorithm.runNextRound(); + Population newPopulation = algorithm.runNextRound(population); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{0, 0, 3, 3, 3, 3, 3, 3, 3, 3})); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{0, 0, 3, 3, 3, 3, 3, 3, 3, 3})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individuals, GeneticAlgorithmFixture) { auto population = Population::makeRandom(m_fitnessMetric, 6, 3, 3) + Population::makeRandom(m_fitnessMetric, 4, 5, 5); + assert(chromosomeLengths(population) == (vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); GenerationalElitistWithExclusivePools::Options options = { /* mutationPoolSize = */ 0.2, @@ -168,12 +121,11 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_not_replace_elite_with_worse_individ /* percentGenesToRandomise = */ 0.0, /* percentGenesToAddOrDelete = */ 1.0, }; - GenerationalElitistWithExclusivePools algorithm(population, m_output, options); - assert(chromosomeLengths(algorithm.population()) == (vector{3, 3, 3, 3, 3, 3, 5, 5, 5, 5})); + GenerationalElitistWithExclusivePools algorithm(options); - algorithm.runNextRound(); + Population newPopulation = algorithm.runNextRound(population); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{3, 3, 3, 3, 3, 3, 3, 3, 7, 7})); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{3, 3, 3, 3, 3, 3, 3, 3, 7, 7})); } BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossover_pool_by_mutating_the_elite, GeneticAlgorithmFixture) @@ -188,13 +140,13 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossove /* percentGenesToRandomise = */ 1.0, /* percentGenesToAddOrDelete = */ 1.0, }; - GenerationalElitistWithExclusivePools algorithm(population, m_output, options); + GenerationalElitistWithExclusivePools algorithm(options); SimulationRNG::reset(1); - algorithm.runNextRound(); + Population newPopulation = algorithm.runNextRound(population); BOOST_TEST(( - chromosomeLengths(algorithm.population()) == + chromosomeLengths(newPopulation) == vector{0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 11, 11, 11} )); } @@ -205,6 +157,7 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossove Population(m_fitnessMetric, {Chromosome("aa"), Chromosome("ff")}) + Population::makeRandom(m_fitnessMetric, 8, 6, 6) ); + assert((chromosomeLengths(population) == vector{2, 2, 6, 6, 6, 6, 6, 6, 6, 6})); GenerationalElitistWithExclusivePools::Options options = { /* mutationPoolSize = */ 0.0, @@ -214,14 +167,13 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_generate_individuals_in_the_crossove /* percentGenesToRandomise = */ 0.0, /* percentGenesToAddOrDelete = */ 0.0, }; - GenerationalElitistWithExclusivePools algorithm(population, m_output, options); - assert((chromosomeLengths(algorithm.population()) == vector{2, 2, 6, 6, 6, 6, 6, 6, 6, 6})); + GenerationalElitistWithExclusivePools algorithm(options); SimulationRNG::reset(1); - algorithm.runNextRound(); + Population newPopulation = algorithm.runNextRound(population); - vector const& newIndividuals = algorithm.population().individuals(); - BOOST_TEST((chromosomeLengths(algorithm.population()) == vector{2, 2, 2, 2, 2, 2, 2, 2, 2, 2})); + vector const& newIndividuals = newPopulation.individuals(); + BOOST_TEST((chromosomeLengths(newPopulation) == vector{2, 2, 2, 2, 2, 2, 2, 2, 2, 2})); for (auto& individual: newIndividuals) BOOST_TEST(( individual.chromosome == Chromosome("aa") || diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index f281439bf1b3..58867e5b9f58 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -15,6 +15,8 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}") add_executable(yul-phaser yulPhaser/main.cpp + yulPhaser/AlgorithmRunner.h + yulPhaser/AlgorithmRunner.cpp yulPhaser/Phaser.h yulPhaser/Phaser.cpp yulPhaser/GeneticAlgorithms.h diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp new file mode 100644 index 000000000000..881f5b46e6b8 --- /dev/null +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -0,0 +1,32 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +using namespace std; +using namespace solidity::phaser; + +void AlgorithmRunner::run(GeneticAlgorithm& _algorithm, optional _numRounds) +{ + for (size_t round = 0; !_numRounds.has_value() || round < _numRounds.value(); ++round) + { + m_population = _algorithm.runNextRound(m_population); + + m_outputStream << "---------- ROUND " << round << " ----------" << endl; + m_outputStream << m_population; + } +} diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h new file mode 100644 index 000000000000..ff436d73b20d --- /dev/null +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -0,0 +1,58 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Contains the implementation of a class that manages the execution of a genetic algorithm. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace solidity::phaser +{ + +/** + * Manages a population and executes a genetic algorithm on it. It's independent of the + * implementation details of a specific algorithm which is pluggable via @a GeneticAlgorithm class. + * + * The class is also responsible for providing text feedback on the execution of the algorithm + * to the associated output stream. + */ +class AlgorithmRunner +{ +public: + AlgorithmRunner( + Population _initialPopulation, + std::ostream& _outputStream + ): + m_population(std::move(_initialPopulation)), + m_outputStream(_outputStream) {} + + void run(GeneticAlgorithm& _algorithm, std::optional _numRounds = std::nullopt); + + Population const& population() const { return m_population; } + +private: + Population m_population; + std::ostream& m_outputStream; +}; + +} diff --git a/tools/yulPhaser/GeneticAlgorithms.cpp b/tools/yulPhaser/GeneticAlgorithms.cpp index fa37ac5e36ee..432f3fe38aae 100644 --- a/tools/yulPhaser/GeneticAlgorithms.cpp +++ b/tools/yulPhaser/GeneticAlgorithms.cpp @@ -23,42 +23,31 @@ using namespace std; using namespace solidity::phaser; -void GeneticAlgorithm::run(optional _numRounds) -{ - for (size_t round = 0; !_numRounds.has_value() || round < _numRounds.value(); ++round) - { - runNextRound(); - - m_outputStream << "---------- ROUND " << round << " ----------" << endl; - m_outputStream << m_population; - } -} - -void RandomAlgorithm::runNextRound() +Population RandomAlgorithm::runNextRound(Population _population) { RangeSelection elite(0.0, m_options.elitePoolSize); - Population elitePopulation = m_population.select(elite); - size_t replacementCount = m_population.individuals().size() - elitePopulation.individuals().size(); + Population elitePopulation = _population.select(elite); + size_t replacementCount = _population.individuals().size() - elitePopulation.individuals().size(); - m_population = + return move(elitePopulation) + Population::makeRandom( - m_population.fitnessMetric(), + _population.fitnessMetric(), replacementCount, m_options.minChromosomeLength, m_options.maxChromosomeLength ); } -void GenerationalElitistWithExclusivePools::runNextRound() +Population GenerationalElitistWithExclusivePools::runNextRound(Population _population) { double elitePoolSize = 1.0 - (m_options.mutationPoolSize + m_options.crossoverPoolSize); RangeSelection elite(0.0, elitePoolSize); - m_population = - m_population.select(elite) + - m_population.select(elite).mutate( + return + _population.select(elite) + + _population.select(elite).mutate( RandomSelection(m_options.mutationPoolSize / elitePoolSize), alternativeMutations( m_options.randomisationChance, @@ -70,7 +59,7 @@ void GenerationalElitistWithExclusivePools::runNextRound() ) ) ) + - m_population.select(elite).crossover( + _population.select(elite).crossover( RandomPairSelection(m_options.crossoverPoolSize / elitePoolSize), randomPointCrossover() ); diff --git a/tools/yulPhaser/GeneticAlgorithms.h b/tools/yulPhaser/GeneticAlgorithms.h index bab475c4edcd..b9ccb4302c52 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -22,45 +22,25 @@ #include -#include -#include - namespace solidity::phaser { /** * Abstract base class for genetic algorithms. - * - * The main feature is the @a run() method that executes the algorithm, updating the internal - * population during each round and printing the results to the stream provided to the constructor. - * - * Derived classes can provide specific methods for updating the population by implementing - * the @a runNextRound() method. + * The main feature is the @a runNextRound() method that executes one round of the algorithm, + * on the supplied population. */ class GeneticAlgorithm { public: - GeneticAlgorithm(Population _initialPopulation, std::ostream& _outputStream): - m_population(std::move(_initialPopulation)), - m_outputStream(_outputStream) {} - + GeneticAlgorithm() {} GeneticAlgorithm(GeneticAlgorithm const&) = delete; GeneticAlgorithm& operator=(GeneticAlgorithm const&) = delete; virtual ~GeneticAlgorithm() = default; - Population const& population() const { return m_population; } - - void run(std::optional _numRounds = std::nullopt); - /// The method that actually implements the algorithm. Should use @a m_population as input and /// replace it with the updated state after the round. - virtual void runNextRound() = 0; - -protected: - Population m_population; - -private: - std::ostream& m_outputStream; + virtual Population runNextRound(Population _population) = 0; }; /** @@ -95,18 +75,13 @@ class RandomAlgorithm: public GeneticAlgorithm } }; - explicit RandomAlgorithm( - Population _initialPopulation, - std::ostream& _outputStream, - Options const& _options - ): - GeneticAlgorithm(_initialPopulation, _outputStream), + explicit RandomAlgorithm(Options const& _options): m_options(_options) { assert(_options.isValid()); } - void runNextRound() override; + Population runNextRound(Population _population) override; private: Options m_options; @@ -148,18 +123,13 @@ class GenerationalElitistWithExclusivePools: public GeneticAlgorithm } }; - GenerationalElitistWithExclusivePools( - Population _initialPopulation, - std::ostream& _outputStream, - Options const& _options - ): - GeneticAlgorithm(_initialPopulation, _outputStream), + GenerationalElitistWithExclusivePools(Options const& _options): m_options(_options) { assert(_options.isValid()); } - void runNextRound() override; + Population runNextRound(Population _population) override; private: Options m_options; diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index a1a955d57c28..0a3e7f66e8af 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -181,37 +182,30 @@ void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm) maxChromosomeLength ); + AlgorithmRunner algorithmRunner(population, cout); switch (_algorithm) { case Algorithm::Random: { - RandomAlgorithm( - population, - cout, - { - /* elitePoolSize = */ 1.0 / populationSize, - /* minChromosomeLength = */ minChromosomeLength, - /* maxChromosomeLength = */ maxChromosomeLength, - } - ).run(); - + RandomAlgorithm algorithm({ + /* elitePoolSize = */ 1.0 / populationSize, + /* minChromosomeLength = */ minChromosomeLength, + /* maxChromosomeLength = */ maxChromosomeLength, + }); + algorithmRunner.run(algorithm); break; } case Algorithm::GEWEP: { - GenerationalElitistWithExclusivePools( - population, - cout, - { - /* mutationPoolSize = */ 0.25, - /* crossoverPoolSize = */ 0.25, - /* randomisationChance = */ 0.9, - /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, - /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, - } - ).run(); - + GenerationalElitistWithExclusivePools algorithm({ + /* mutationPoolSize = */ 0.25, + /* crossoverPoolSize = */ 0.25, + /* randomisationChance = */ 0.9, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, + /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, + }); + algorithmRunner.run(algorithm); break; } } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 65a82eba49e1..07b7426ab9c5 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -41,7 +41,7 @@ std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorith /** * Main class that controls yul-phaser based on command-line parameters. The class is responsible * for command-line parsing, initialisation of global objects (like the random number generator), - * creating instances of main components and running the genetic algorithm. + * creating instances of main components and feeding them into @a AlgorithmRunner. */ class Phaser { From 2110bf10cf43e26a95b8914d8559077794f524ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 19:46:18 +0100 Subject: [PATCH 030/165] [yul-phaser] AlgorithmRunner: Create a structure to store runner's options --- test/yulPhaser/AlgorithmRunner.cpp | 18 ++++++++++++------ tools/yulPhaser/AlgorithmRunner.cpp | 4 ++-- tools/yulPhaser/AlgorithmRunner.h | 11 ++++++++++- tools/yulPhaser/Phaser.cpp | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 16a4dd8936c0..0270e4b83c73 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -50,6 +50,7 @@ class AlgorithmRunnerFixture protected: shared_ptr m_fitnessMetric = make_shared(); output_test_stream m_output; + AlgorithmRunner::Options m_options; }; BOOST_AUTO_TEST_SUITE(Phaser) @@ -57,33 +58,38 @@ BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRunnerFixture) { - AlgorithmRunner runner(Population(m_fitnessMetric), m_output); + m_options.maxRounds = 5; + AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output); DummyAlgorithm algorithm; BOOST_TEST(algorithm.m_currentRound == 0); - runner.run(algorithm, 10); + runner.run(algorithm); + BOOST_TEST(algorithm.m_currentRound == 5); + runner.run(algorithm); BOOST_TEST(algorithm.m_currentRound == 10); - runner.run(algorithm, 3); - BOOST_TEST(algorithm.m_currentRound == 13); } BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixture) { // run() is allowed to print more but should at least print the first one + m_options.maxRounds = 1; AlgorithmRunner runner( // NOTE: Chromosomes chosen so that they're not substrings of each other and are not // words likely to appear in the output in normal circumstances. Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), + m_options, m_output ); DummyAlgorithm algorithm; BOOST_TEST(m_output.is_empty()); - runner.run(algorithm, 1); + runner.run(algorithm); BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 1); - runner.run(algorithm, 3); + runner.run(algorithm); + runner.run(algorithm); + runner.run(algorithm); BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4); } diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 881f5b46e6b8..bd5ce5755250 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -20,9 +20,9 @@ using namespace std; using namespace solidity::phaser; -void AlgorithmRunner::run(GeneticAlgorithm& _algorithm, optional _numRounds) +void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) { - for (size_t round = 0; !_numRounds.has_value() || round < _numRounds.value(); ++round) + for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { m_population = _algorithm.runNextRound(m_population); diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index ff436d73b20d..c0aaa562134b 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -39,19 +39,28 @@ namespace solidity::phaser class AlgorithmRunner { public: + struct Options + { + std::optional maxRounds = std::nullopt; + }; + AlgorithmRunner( Population _initialPopulation, + Options _options, std::ostream& _outputStream ): m_population(std::move(_initialPopulation)), + m_options(std::move(_options)), m_outputStream(_outputStream) {} - void run(GeneticAlgorithm& _algorithm, std::optional _numRounds = std::nullopt); + void run(GeneticAlgorithm& _algorithm); + Options const& options() const { return m_options; } Population const& population() const { return m_population; } private: Population m_population; + Options m_options; std::ostream& m_outputStream; }; diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 0a3e7f66e8af..7708e85baec4 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -182,7 +182,7 @@ void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm) maxChromosomeLength ); - AlgorithmRunner algorithmRunner(population, cout); + AlgorithmRunner algorithmRunner(population, AlgorithmRunner::Options{}, cout); switch (_algorithm) { case Algorithm::Random: From 25e81f6bd35f4e38d0ee56a6d402a85f482b1e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 00:44:36 +0100 Subject: [PATCH 031/165] [yul-phaser] AlgorithmRunner: Count rounds from 1 --- tools/yulPhaser/AlgorithmRunner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index bd5ce5755250..0efe19b7c7b1 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -26,7 +26,7 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) { m_population = _algorithm.runNextRound(m_population); - m_outputStream << "---------- ROUND " << round << " ----------" << endl; + m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; m_outputStream << m_population; } } From 2d177c76231fca864d7fe6fb791420e309bfa6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 17:18:13 +0100 Subject: [PATCH 032/165] [yul-phaser] Phaser: Refactor object creation in runAlgorithm() into a set of factories --- tools/yulPhaser/Phaser.cpp | 130 ++++++++++++++++++++++++------------- tools/yulPhaser/Phaser.h | 88 ++++++++++++++++++++++++- 2 files changed, 169 insertions(+), 49 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 7708e85baec4..c03cf9369da9 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -68,10 +68,77 @@ ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) return _outputStream; } -namespace +GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments) { + return { + _arguments["algorithm"].as(), + }; +} -CharStream loadSource(string const& _sourcePath) +unique_ptr GeneticAlgorithmFactory::build( + Options const& _options, + size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength +) +{ + assert(_populationSize > 0); + + switch (_options.algorithm) + { + case Algorithm::Random: + return make_unique(RandomAlgorithm::Options{ + /* elitePoolSize = */ 1.0 / _populationSize, + /* minChromosomeLength = */ _minChromosomeLength, + /* maxChromosomeLength = */ _maxChromosomeLength, + }); + case Algorithm::GEWEP: + return make_unique(GenerationalElitistWithExclusivePools::Options{ + /* mutationPoolSize = */ 0.25, + /* crossoverPoolSize = */ 0.25, + /* randomisationChance = */ 0.9, + /* deletionVsAdditionChance = */ 0.5, + /* percentGenesToRandomise = */ 1.0 / _maxChromosomeLength, + /* percentGenesToAddOrDelete = */ 1.0 / _maxChromosomeLength, + }); + default: + assertThrow(false, solidity::util::Exception, "Invalid Algorithm value."); + } +} + +unique_ptr FitnessMetricFactory::build( + Program _program +) +{ + return make_unique(move(_program), RepetitionCount); +} + +Population PopulationFactory::build( + shared_ptr _fitnessMetric +) +{ + return Population::makeRandom( + move(_fitnessMetric), + PopulationSize, + MinChromosomeLength, + MaxChromosomeLength + ); +} + +ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["input-file"].as(), + }; +} + +Program ProgramFactory::build(Options const& _options) +{ + CharStream sourceCode = loadSource(_options.inputFile); + return Program::load(sourceCode); +} + +CharStream ProgramFactory::loadSource(string const& _sourcePath) { assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); @@ -79,8 +146,6 @@ CharStream loadSource(string const& _sourcePath) return CharStream(sourceCode, _sourcePath); } -} - int Phaser::main(int _argc, char** _argv) { CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv); @@ -89,10 +154,7 @@ int Phaser::main(int _argc, char** _argv) initialiseRNG(parsingResult.arguments); - runAlgorithm( - parsingResult.arguments["input-file"].as(), - parsingResult.arguments["algorithm"].as() - ); + runAlgorithm(parsingResult.arguments); return 0; } @@ -167,46 +229,22 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments) cout << "Random seed: " << seed << endl; } -void Phaser::runAlgorithm(string const& _sourcePath, Algorithm _algorithm) +void Phaser::runAlgorithm(po::variables_map const& _arguments) { - constexpr size_t populationSize = 20; - constexpr size_t minChromosomeLength = 12; - constexpr size_t maxChromosomeLength = 30; - - CharStream sourceCode = loadSource(_sourcePath); - shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5); - auto population = Population::makeRandom( - fitnessMetric, - populationSize, - minChromosomeLength, - maxChromosomeLength + auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); + auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); + + Program program = ProgramFactory::build(programOptions); + unique_ptr fitnessMetric = FitnessMetricFactory::build(move(program)); + Population population = PopulationFactory::build(move(fitnessMetric)); + + unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( + algorithmOptions, + population.individuals().size(), + PopulationFactory::MinChromosomeLength, + PopulationFactory::MaxChromosomeLength ); AlgorithmRunner algorithmRunner(population, AlgorithmRunner::Options{}, cout); - switch (_algorithm) - { - case Algorithm::Random: - { - RandomAlgorithm algorithm({ - /* elitePoolSize = */ 1.0 / populationSize, - /* minChromosomeLength = */ minChromosomeLength, - /* maxChromosomeLength = */ maxChromosomeLength, - }); - algorithmRunner.run(algorithm); - break; - } - case Algorithm::GEWEP: - { - GenerationalElitistWithExclusivePools algorithm({ - /* mutationPoolSize = */ 0.25, - /* crossoverPoolSize = */ 0.25, - /* randomisationChance = */ 0.9, - /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 1.0 / maxChromosomeLength, - /* percentGenesToAddOrDelete = */ 1.0 / maxChromosomeLength, - }); - algorithmRunner.run(algorithm); - break; - } - } + algorithmRunner.run(*geneticAlgorithm); } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 07b7426ab9c5..1afd0836f6f9 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -15,7 +15,8 @@ along with solidity. If not, see . */ /** - * Contains the main class that controls yul-phaser based on command-line parameters. + * Contains the main class that controls yul-phaser based on command-line parameters and + * associated factories for building instances of phaser's components. */ #pragma once @@ -23,12 +24,25 @@ #include #include +#include #include #include +namespace solidity::langutil +{ + +class CharStream; + +} + namespace solidity::phaser { +class FitnessMetric; +class GeneticAlgorithm; +class Population; +class Program; + enum class Algorithm { Random, @@ -38,10 +52,78 @@ enum class Algorithm std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); +/** + * Builds and validates instances of @a GeneticAlgorithm and its derived classes. + */ +class GeneticAlgorithmFactory +{ +public: + struct Options + { + Algorithm algorithm; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static std::unique_ptr build( + Options const& _options, + size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength + ); +}; + +/** + * Builds and validates instances of @a FitnessMetric and its derived classes. + */ +class FitnessMetricFactory +{ +public: + static constexpr size_t RepetitionCount = 5; + + static std::unique_ptr build( + Program _program + ); +}; + +/** + * Builds and validates instances of @a Population. + */ +class PopulationFactory +{ +public: + static constexpr size_t PopulationSize = 20; + static constexpr size_t MinChromosomeLength = 12; + static constexpr size_t MaxChromosomeLength = 30; + + static Population build( + std::shared_ptr _fitnessMetric + ); +}; + +/** + * Builds and validates instances of @a Program. + */ +class ProgramFactory +{ +public: + struct Options + { + std::string inputFile; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static Program build(Options const& _options); + +private: + static langutil::CharStream loadSource(std::string const& _sourcePath); +}; + /** * Main class that controls yul-phaser based on command-line parameters. The class is responsible * for command-line parsing, initialisation of global objects (like the random number generator), - * creating instances of main components and feeding them into @a AlgorithmRunner. + * creating instances of main components using factories and feeding them into @a AlgorithmRunner. */ class Phaser { @@ -58,7 +140,7 @@ class Phaser static CommandLineParsingResult parseCommandLine(int _argc, char** _argv); static void initialiseRNG(boost::program_options::variables_map const& _arguments); - static void runAlgorithm(std::string const& _sourcePath, Algorithm _algorithm); + static void runAlgorithm(boost::program_options::variables_map const& _arguments); }; } From 7cf5c4e266645d3c78a7e3c5b3c8769ad16eab14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 19:23:33 +0100 Subject: [PATCH 033/165] [yul-phaser] Phaser: Extract preparation of option description into a separate function --- tools/yulPhaser/Phaser.cpp | 28 +++++++++++++++++++--------- tools/yulPhaser/Phaser.h | 7 +++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index c03cf9369da9..ac96a1ee873a 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -158,9 +158,12 @@ int Phaser::main(int _argc, char** _argv) return 0; } -Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _argv) +Phaser::CommandLineDescription Phaser::buildCommandLineDescription() { - po::options_description description( + size_t const lineLength = po::options_description::m_default_line_length; + size_t const minDescriptionLength = lineLength - 23; + + po::options_description keywordDescription( "yul-phaser, a tool for finding the best sequence of Yul optimisation phases.\n" "\n" "Usage: yul-phaser [options] \n" @@ -170,11 +173,10 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg "yul-phaser program.yul\n" "\n" "Allowed options", - po::options_description::m_default_line_length, - po::options_description::m_default_line_length - 23 + lineLength, + minDescriptionLength ); - - description.add_options() + keywordDescription.add_options() ("help", "Show help message and exit.") ("input-file", po::value()->required(), "Input file") ("seed", po::value(), "Seed for the random number generator") @@ -186,14 +188,22 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg ; po::positional_options_description positionalDescription; - po::variables_map arguments; positionalDescription.add("input-file", 1); + + return {keywordDescription, positionalDescription}; +} + +Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _argv) +{ + auto [keywordDescription, positionalDescription] = buildCommandLineDescription(); + + po::variables_map arguments; po::notify(arguments); try { po::command_line_parser parser(_argc, _argv); - parser.options(description).positional(positionalDescription); + parser.options(keywordDescription).positional(positionalDescription); po::store(parser.run(), arguments); } catch (po::error const & _exception) @@ -204,7 +214,7 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg if (arguments.count("help") > 0) { - cout << description << endl; + cout << keywordDescription << endl; return {2, move(arguments)}; } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 1afd0836f6f9..75025557691d 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -131,12 +131,19 @@ class Phaser static int main(int argc, char** argv); private: + struct CommandLineDescription + { + boost::program_options::options_description keywordDescription; + boost::program_options::positional_options_description positionalDescription; + }; + struct CommandLineParsingResult { int exitCode; boost::program_options::variables_map arguments; }; + static CommandLineDescription buildCommandLineDescription(); static CommandLineParsingResult parseCommandLine(int _argc, char** _argv); static void initialiseRNG(boost::program_options::variables_map const& _arguments); From ffc21632b6a519b761069dc0c800605345321cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 19:03:10 +0100 Subject: [PATCH 034/165] [yul-phaser] Phaser: Split command-line option description into groups --- tools/yulPhaser/Phaser.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index ac96a1ee873a..c06533c21fe7 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -176,16 +176,25 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() lineLength, minDescriptionLength ); - keywordDescription.add_options() + + po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength); + generalDescription.add_options() ("help", "Show help message and exit.") ("input-file", po::value()->required(), "Input file") ("seed", po::value(), "Seed for the random number generator") + ; + keywordDescription.add(generalDescription); + + po::options_description algorithmDescription("ALGORITHM", lineLength, minDescriptionLength); + algorithmDescription.add_options() ( "algorithm", po::value()->default_value(Algorithm::GEWEP), "Algorithm" ) ; + keywordDescription.add(algorithmDescription); + po::positional_options_description positionalDescription; positionalDescription.add("input-file", 1); From df90cf5d7a9a5c69c3eecc2cc844434d461ed5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 19:40:02 +0100 Subject: [PATCH 035/165] [yul-phaser] Phaser: Make all option descriptions consistenly end with a full stop --- tools/yulPhaser/Phaser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index c06533c21fe7..ba99f3544683 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -180,8 +180,8 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength); generalDescription.add_options() ("help", "Show help message and exit.") - ("input-file", po::value()->required(), "Input file") - ("seed", po::value(), "Seed for the random number generator") + ("input-file", po::value()->required(), "Input file.") + ("seed", po::value(), "Seed for the random number generator.") ; keywordDescription.add(generalDescription); From a80512a71d2c5836324ee5e59e401d1a80c45cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 18:52:56 +0100 Subject: [PATCH 036/165] [yul-phaser] Phaser: Name option parameters in command-line help --- tools/yulPhaser/Phaser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index ba99f3544683..45d9672d19a8 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -180,8 +180,8 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength); generalDescription.add_options() ("help", "Show help message and exit.") - ("input-file", po::value()->required(), "Input file.") - ("seed", po::value(), "Seed for the random number generator.") + ("input-file", po::value()->required()->value_name(""), "Input file.") + ("seed", po::value()->value_name(""), "Seed for the random number generator.") ; keywordDescription.add(generalDescription); @@ -189,7 +189,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() algorithmDescription.add_options() ( "algorithm", - po::value()->default_value(Algorithm::GEWEP), + po::value()->value_name("")->default_value(Algorithm::GEWEP), "Algorithm" ) ; From d01dab7b7c18a797d11df4f4118568599d002f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 2 Mar 2020 09:38:36 +0100 Subject: [PATCH 037/165] [yul-phaser] Rename Common to Helpers in tests (file move) - I want to add Common.h in the non-test code and it's getting confusing. I think it's better to have them named differently. --- test/yulPhaser/{Common.cpp => TestHelpers.cpp} | 0 test/yulPhaser/{Common.h => TestHelpers.h} | 0 test/yulPhaser/{CommonTest.cpp => TestHelpersTest.cpp} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/yulPhaser/{Common.cpp => TestHelpers.cpp} (100%) rename test/yulPhaser/{Common.h => TestHelpers.h} (100%) rename test/yulPhaser/{CommonTest.cpp => TestHelpersTest.cpp} (100%) diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/TestHelpers.cpp similarity index 100% rename from test/yulPhaser/Common.cpp rename to test/yulPhaser/TestHelpers.cpp diff --git a/test/yulPhaser/Common.h b/test/yulPhaser/TestHelpers.h similarity index 100% rename from test/yulPhaser/Common.h rename to test/yulPhaser/TestHelpers.h diff --git a/test/yulPhaser/CommonTest.cpp b/test/yulPhaser/TestHelpersTest.cpp similarity index 100% rename from test/yulPhaser/CommonTest.cpp rename to test/yulPhaser/TestHelpersTest.cpp From 099299c5e7cbbf435adc074802829c2f5023c5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 2 Mar 2020 09:40:58 +0100 Subject: [PATCH 038/165] [yul-phaser] Rename Common to Helpers in tests (update references) --- test/CMakeLists.txt | 6 +++--- test/yulPhaser/AlgorithmRunner.cpp | 2 +- test/yulPhaser/Chromosome.cpp | 2 +- test/yulPhaser/GeneticAlgorithms.cpp | 2 +- test/yulPhaser/Mutations.cpp | 2 +- test/yulPhaser/PairSelections.cpp | 2 +- test/yulPhaser/Population.cpp | 2 +- test/yulPhaser/Program.cpp | 2 +- test/yulPhaser/Selections.cpp | 2 +- test/yulPhaser/SimulationRNG.cpp | 2 +- test/yulPhaser/TestHelpers.cpp | 2 +- test/yulPhaser/TestHelpersTest.cpp | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d78711634759..14b8094a1af6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -139,9 +139,9 @@ set(libyul_sources detect_stray_source_files("${libyul_sources}" "libyul/") set(yul_phaser_sources - yulPhaser/Common.h - yulPhaser/Common.cpp - yulPhaser/CommonTest.cpp + yulPhaser/TestHelpers.h + yulPhaser/TestHelpers.cpp + yulPhaser/TestHelpersTest.cpp yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp yulPhaser/AlgorithmRunner.cpp diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 0270e4b83c73..f6102a9cb670 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index 23de34a2dce3..442f7967f612 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index 13a3116692d0..f7a5e7a92dc4 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index 66852ed55089..df58cec540d9 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include diff --git a/test/yulPhaser/PairSelections.cpp b/test/yulPhaser/PairSelections.cpp index af03cd2bcae6..64109470f6ed 100644 --- a/test/yulPhaser/PairSelections.cpp +++ b/test/yulPhaser/PairSelections.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/Population.cpp b/test/yulPhaser/Population.cpp index 2363256e44ae..7a9172749bb7 100644 --- a/test/yulPhaser/Population.cpp +++ b/test/yulPhaser/Population.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/Program.cpp b/test/yulPhaser/Program.cpp index 7d9c81cd3427..5c1d2a6e6c1d 100644 --- a/test/yulPhaser/Program.cpp +++ b/test/yulPhaser/Program.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/Selections.cpp b/test/yulPhaser/Selections.cpp index ce870ce80273..02a85f4f33b5 100644 --- a/test/yulPhaser/Selections.cpp +++ b/test/yulPhaser/Selections.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include #include diff --git a/test/yulPhaser/SimulationRNG.cpp b/test/yulPhaser/SimulationRNG.cpp index f158fcbf6aa4..0cdacc428d63 100644 --- a/test/yulPhaser/SimulationRNG.cpp +++ b/test/yulPhaser/SimulationRNG.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include diff --git a/test/yulPhaser/TestHelpers.cpp b/test/yulPhaser/TestHelpers.cpp index f9000921f614..b52cee084e89 100644 --- a/test/yulPhaser/TestHelpers.cpp +++ b/test/yulPhaser/TestHelpers.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include diff --git a/test/yulPhaser/TestHelpersTest.cpp b/test/yulPhaser/TestHelpersTest.cpp index efc511a80e62..98d609050693 100644 --- a/test/yulPhaser/TestHelpersTest.cpp +++ b/test/yulPhaser/TestHelpersTest.cpp @@ -15,7 +15,7 @@ along with solidity. If not, see . */ -#include +#include #include @@ -31,7 +31,7 @@ namespace solidity::phaser::test { BOOST_AUTO_TEST_SUITE(Phaser) -BOOST_AUTO_TEST_SUITE(CommonTest) +BOOST_AUTO_TEST_SUITE(TestHelpersTest) BOOST_AUTO_TEST_CASE(ChromosomeLengthMetric_evaluate_should_return_chromosome_length) { From 0c3de9ef9931d545ad524dd9595b49c71c0871ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 2 Mar 2020 10:19:44 +0100 Subject: [PATCH 039/165] [yul-phaser] Add Common module --- test/CMakeLists.txt | 1 + test/yulPhaser/Common.cpp | 30 ++++++++++++++++++++++++++++++ tools/CMakeLists.txt | 1 + tools/yulPhaser/Common.h | 26 ++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 test/yulPhaser/Common.cpp create mode 100644 tools/yulPhaser/Common.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 14b8094a1af6..fa9127e7223f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -142,6 +142,7 @@ set(yul_phaser_sources yulPhaser/TestHelpers.h yulPhaser/TestHelpers.cpp yulPhaser/TestHelpersTest.cpp + yulPhaser/Common.cpp yulPhaser/Chromosome.cpp yulPhaser/FitnessMetrics.cpp yulPhaser/AlgorithmRunner.cpp diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp new file mode 100644 index 000000000000..e045a9a8c100 --- /dev/null +++ b/test/yulPhaser/Common.cpp @@ -0,0 +1,30 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +namespace solidity::phaser::test +{ + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(CommonTest) +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 58867e5b9f58..fb2d411b5bd6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -15,6 +15,7 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}") add_executable(yul-phaser yulPhaser/main.cpp + yulPhaser/Common.h yulPhaser/AlgorithmRunner.h yulPhaser/AlgorithmRunner.cpp yulPhaser/Phaser.h diff --git a/tools/yulPhaser/Common.h b/tools/yulPhaser/Common.h new file mode 100644 index 000000000000..ae5b9ebd3454 --- /dev/null +++ b/tools/yulPhaser/Common.h @@ -0,0 +1,26 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** + * Miscellaneous utilities for use in yul-phaser. + */ + +#pragma once + +namespace solidity::phaser +{ + +} From deaf1d0c6f44092428dc9aaf45cd9d87356b5c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 2 Mar 2020 10:20:28 +0100 Subject: [PATCH 040/165] [yul-phaser] Add serializeChoice() and deserializeChoice() --- test/yulPhaser/Common.cpp | 99 +++++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Common.h | 42 +++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp index e045a9a8c100..891495193049 100644 --- a/test/yulPhaser/Common.cpp +++ b/test/yulPhaser/Common.cpp @@ -17,13 +17,112 @@ #include +#include + #include +#include + +#include +#include + +using namespace std; +using namespace boost::test_tools; +using namespace solidity::util; namespace solidity::phaser::test { +namespace +{ + +enum class TestEnum +{ + A, + B, + AB, + CD, + EF, + GH, +}; + +map const TestEnumToStringMap = +{ + {TestEnum::A, "a"}, + {TestEnum::B, "b"}, + {TestEnum::AB, "a b"}, + {TestEnum::CD, "c-d"}, + {TestEnum::EF, "e f"}, +}; +map const StringToTestEnumMap = invertMap(TestEnumToStringMap); + +} + BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(CommonTest) + +BOOST_AUTO_TEST_CASE(deserializeChoice_should_convert_string_to_enum) +{ + istringstream aStream("a"); + TestEnum aResult; + deserializeChoice(aStream, aResult, StringToTestEnumMap); + BOOST_CHECK(aResult == TestEnum::A); + BOOST_TEST(!aStream.fail()); + + istringstream bStream("b"); + TestEnum bResult; + deserializeChoice(bStream, bResult, StringToTestEnumMap); + BOOST_CHECK(bResult == TestEnum::B); + BOOST_TEST(!bStream.fail()); + + istringstream cdStream("c-d"); + TestEnum cdResult; + deserializeChoice(cdStream, cdResult, StringToTestEnumMap); + BOOST_CHECK(cdResult == TestEnum::CD); + BOOST_TEST(!cdStream.fail()); +} + +BOOST_AUTO_TEST_CASE(deserializeChoice_should_set_failbit_if_there_is_no_enum_corresponding_to_string) +{ + istringstream xyzStream("xyz"); + TestEnum xyzResult; + deserializeChoice(xyzStream, xyzResult, StringToTestEnumMap); + BOOST_TEST(xyzStream.fail()); +} + +BOOST_AUTO_TEST_CASE(deserializeChoice_does_not_have_to_support_strings_with_spaces) +{ + istringstream abStream("a b"); + TestEnum abResult; + deserializeChoice(abStream, abResult, StringToTestEnumMap); + BOOST_CHECK(abResult == TestEnum::A); + BOOST_TEST(!abStream.fail()); + + istringstream efStream("e f"); + TestEnum efResult; + deserializeChoice(efStream, efResult, StringToTestEnumMap); + BOOST_TEST(efStream.fail()); +} + +BOOST_AUTO_TEST_CASE(serializeChoice_should_convert_enum_to_string) +{ + output_test_stream output; + + serializeChoice(output, TestEnum::A, TestEnumToStringMap); + BOOST_CHECK(output.is_equal("a")); + BOOST_TEST(!output.fail()); + + serializeChoice(output, TestEnum::AB, TestEnumToStringMap); + BOOST_CHECK(output.is_equal("a b")); + BOOST_TEST(!output.fail()); +} + +BOOST_AUTO_TEST_CASE(serializeChoice_should_set_failbit_if_there_is_no_string_corresponding_to_enum) +{ + output_test_stream output; + serializeChoice(output, TestEnum::GH, TestEnumToStringMap); + BOOST_TEST(output.fail()); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/Common.h b/tools/yulPhaser/Common.h index ae5b9ebd3454..9bf3f6204e81 100644 --- a/tools/yulPhaser/Common.h +++ b/tools/yulPhaser/Common.h @@ -20,7 +20,49 @@ #pragma once +#include +#include + namespace solidity::phaser { +/// Reads a token from the input stream and translates it to a string using a map. +/// Sets the failbit in the stream if there's no matching value in the map. +template +std::istream& deserializeChoice( + std::istream& _inputStream, + C& _choice, + std::map const& _stringToValueMap +) +{ + std::string deserializedValue; + _inputStream >> deserializedValue; + + auto const& pair = _stringToValueMap.find(deserializedValue); + if (pair != _stringToValueMap.end()) + _choice = pair->second; + else + _inputStream.setstate(std::ios_base::failbit); + + return _inputStream; +} + +/// Translates a value to a string using a map and prints it to the output stream. +/// Sets the failbit if the value is not in the map. +template +std::ostream& serializeChoice( + std::ostream& _outputStream, + C const& _choice, + std::map const& _valueToStringMap +) +{ + auto const& pair = _valueToStringMap.find(_choice); + if (pair != _valueToStringMap.end()) + _outputStream << pair->second; + else + _outputStream.setstate(std::ios_base::failbit); + + return _outputStream; +} + } From 98fcba8ef3a8657dfa9019543ccdf6f543c169da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 16:20:44 +0100 Subject: [PATCH 041/165] [yul-phaser] Phaser: Reimplement << and >> operators using serializeChoice() and deserializeChoice() --- tools/yulPhaser/Phaser.cpp | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 45d9672d19a8..44fb9d130124 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include #include @@ -41,33 +43,21 @@ using namespace solidity::phaser; namespace po = boost::program_options; -istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) +namespace { - string value; - _inputStream >> value; - if (value == "random") - _algorithm = Algorithm::Random; - else if (value == "GEWEP") - _algorithm = Algorithm::GEWEP; - else - _inputStream.setstate(ios_base::failbit); - - return _inputStream; -} - -ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) +map const AlgorithmToStringMap = { - if (_algorithm == Algorithm::Random) - _outputStream << "random"; - else if (_algorithm == Algorithm::GEWEP) - _outputStream << "GEWEP"; - else - _outputStream.setstate(ios_base::failbit); + {Algorithm::Random, "random"}, + {Algorithm::GEWEP, "GEWEP"}, +}; +map const StringToAlgorithmMap = invertMap(AlgorithmToStringMap); - return _outputStream; } +istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) { return deserializeChoice(_inputStream, _algorithm, StringToAlgorithmMap); } +ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) { return serializeChoice(_outputStream, _algorithm, AlgorithmToStringMap); } + GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { From 96d278b101ed4265e2a9f47fca0801e91624dee2 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 6 Mar 2020 20:59:34 +0100 Subject: [PATCH 042/165] [Sol->Yul] Adding slicing for call data arrays --- libsolidity/codegen/ExpressionCompiler.cpp | 27 ++++----- libsolidity/codegen/YulUtilFunctions.cpp | 53 ++++++++++++++++++ libsolidity/codegen/YulUtilFunctions.h | 5 ++ .../codegen/ir/IRGeneratorForStatements.cpp | 56 +++++++++++++++++-- .../array/calldata_slice_access.sol | 2 + .../calldata_array_index_range_access.sol | 45 +++++++++++++++ 6 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 2b6285c0afa2..d4f3d460da08 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1800,6 +1800,7 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) { CompilerContext::LocationSetter locationSetter(m_context, _indexAccess); _indexAccess.baseExpression().accept(*this); + // stack: offset length Type const& baseType = *_indexAccess.baseExpression().annotation().type; @@ -1815,27 +1816,21 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) acceptAndConvert(*_indexAccess.startExpression(), *TypeProvider::uint256()); else m_context << u256(0); + // stack: offset length sliceStart + + m_context << Instruction::SWAP1; + // stack: offset sliceStart length + if (_indexAccess.endExpression()) acceptAndConvert(*_indexAccess.endExpression(), *TypeProvider::uint256()); else - m_context << Instruction::DUP2; + m_context << Instruction::DUP1; + // stack: offset sliceStart length sliceEnd - m_context.appendInlineAssembly( - Whiskers(R"({ - if gt(sliceStart, sliceEnd) { } - if gt(sliceEnd, length) { } - - offset := add(offset, mul(sliceStart, )) - length := sub(sliceEnd, sliceStart) - })") - ("stride", toString(arrayType->calldataStride())) - ("revertStringStartEnd", m_context.revertReasonIfDebug("Slice starts after end")) - ("revertStringEndLength", m_context.revertReasonIfDebug("Slice is greater than length")) - .render(), - {"offset", "length", "sliceStart", "sliceEnd"} - ); + m_context << Instruction::SWAP3; + // stack: sliceEnd sliceStart length offset - m_context << Instruction::POP << Instruction::POP; + m_context.callYulFunction(m_context.utilFunctions().calldataArrayIndexRangeAccess(*arrayType), 4, 2); return false; } diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 046769e43169..ba664dbb641f 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -933,6 +933,28 @@ string YulUtilFunctions::calldataArrayIndexAccessFunction(ArrayType const& _type }); } +string YulUtilFunctions::calldataArrayIndexRangeAccess(ArrayType const& _type) +{ + solAssert(_type.dataStoredIn(DataLocation::CallData), ""); + solAssert(_type.isDynamicallySized(), ""); + string functionName = "calldata_array_index_range_access_" + _type.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function (offset, length, startIndex, endIndex) -> offsetOut, lengthOut { + if gt(startIndex, endIndex) { } + if gt(endIndex, length) { } + offsetOut := add(offset, mul(startIndex, )) + lengthOut := sub(endIndex, startIndex) + } + )") + ("functionName", functionName) + ("stride", to_string(_type.calldataStride())) + ("revertSliceStartAfterEnd", revertReasonIfDebug("Slice starts after end")) + ("revertSliceGreaterThanLength", revertReasonIfDebug("Slice is greater than length")) + .render(); + }); +} + string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) { solAssert(_type.isDynamicallyEncoded(), ""); @@ -1365,6 +1387,37 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) }); } + if (_from.category() == Type::Category::ArraySlice) + { + solAssert(_from.isDynamicallySized(), ""); + solAssert(_from.dataStoredIn(DataLocation::CallData), ""); + solAssert(_to.category() == Type::Category::Array, ""); + + ArraySliceType const& fromType = dynamic_cast(_from); + ArrayType const& targetType = dynamic_cast(_to); + + solAssert( + *fromType.arrayType().baseType() == *targetType.baseType(), + "Converting arrays of different type is not possible" + ); + + string const functionName = + "convert_" + + _from.identifier() + + "_to_" + + _to.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function (offset, length) -> outOffset, outLength { + outOffset := offset + outLength := length + } + )") + ("functionName", functionName) + .render(); + }); + } + if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1) return conversionFunctionSpecial(_from, _to); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index cf50c785f4c2..8841e98adf92 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -175,6 +175,11 @@ class YulUtilFunctions /// signature: (baseRef, index) -> offset[, length] std::string calldataArrayIndexAccessFunction(ArrayType const& _type); + /// @returns the name of a function that returns offset and length for array slice + /// for the given array offset, length and start and end indices for slice + /// signature: (arrayOffset, arrayLength, sliceStart, sliceEnd) -> offset, length + std::string calldataArrayIndexRangeAccess(ArrayType const& _type); + /// @returns the name of a function that follows a calldata tail while performing /// bounds checks. /// signature: (baseRef, tailPointer) -> offset[, length] diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 5a413a4494f5..21a105db5c6f 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1001,9 +1001,16 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) } }); } - else if (baseType.category() == Type::Category::Array) + else if (baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice) { - ArrayType const& arrayType = dynamic_cast(baseType); + ArrayType const& arrayType = + baseType.category() == Type::Category::Array ? + dynamic_cast(baseType) : + dynamic_cast(baseType).arrayType(); + + if (baseType.category() == Type::Category::ArraySlice) + solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized(), ""); + solAssert(_indexAccess.indexExpression(), "Index expression expected."); switch (arrayType.location()) @@ -1086,9 +1093,50 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) solAssert(false, "Index access only allowed for mappings or arrays."); } -void IRGeneratorForStatements::endVisit(IndexRangeAccess const&) +void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAccess) { - solUnimplementedAssert(false, "Index range accesses not yet implemented."); + Type const& baseType = *_indexRangeAccess.baseExpression().annotation().type; + solAssert( + baseType.category() == Type::Category::Array || baseType.category() == Type::Category::ArraySlice, + "Index range accesses is available only on arrays and array slices." + ); + + ArrayType const& arrayType = + baseType.category() == Type::Category::Array ? + dynamic_cast(baseType) : + dynamic_cast(baseType).arrayType(); + + switch (arrayType.location()) + { + case DataLocation::CallData: + { + solAssert(baseType.isDynamicallySized(), ""); + IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()}; + if (_indexRangeAccess.startExpression()) + define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()}); + else + define(sliceStart) << u256(0) << "\n"; + + IRVariable sliceEnd{ + m_context.newYulVariable(), + *TypeProvider::uint256() + }; + if (_indexRangeAccess.endExpression()) + define(sliceEnd, IRVariable{*_indexRangeAccess.endExpression()}); + else + define(sliceEnd, IRVariable{_indexRangeAccess.baseExpression()}.part("length")); + + IRVariable range{_indexRangeAccess}; + define(range) << + m_utils.calldataArrayIndexRangeAccess(arrayType) << "(" << + IRVariable{_indexRangeAccess.baseExpression()}.commaSeparatedList() << ", " << + sliceStart.name() << ", " << + sliceEnd.name() << ")\n"; + break; + } + default: + solUnimplementedAssert(false, "Index range accesses is implemented only on calldata arrays."); + } } void IRGeneratorForStatements::endVisit(Identifier const& _identifier) diff --git a/test/libsolidity/semanticTests/array/calldata_slice_access.sol b/test/libsolidity/semanticTests/array/calldata_slice_access.sol index 8e8a398de268..7eb975677aa7 100644 --- a/test/libsolidity/semanticTests/array/calldata_slice_access.sol +++ b/test/libsolidity/semanticTests/array/calldata_slice_access.sol @@ -6,6 +6,8 @@ contract C { return (x[start:end][index], x[start:][0:end-start][index], x[:end][start:][index]); } } +// ==== +// compileViaYul: also // ---- // f(uint256[],uint256,uint256): 0x80, 0, 0, 0, 1, 42 -> // f(uint256[],uint256,uint256): 0x80, 0, 1, 0, 1, 42 -> diff --git a/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol b/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol new file mode 100644 index 000000000000..d0e4ee59507e --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/calldata_array_index_range_access.sol @@ -0,0 +1,45 @@ +pragma experimental ABIEncoderV2; +contract C { + function f(uint256[] calldata x, uint256 s, uint256 e) external returns (uint256) { + return uint256[](x[s:e]).length; + } + function f(uint256[] calldata x, uint256 s, uint256 e, uint256 ss, uint256 ee) external returns (uint256) { + return uint256[](x[s:e][ss:ee]).length; + } + function f_s_only(uint256[] calldata x, uint256 s) external returns (uint256) { + return uint256[](x[s:]).length; + } + function f_e_only(uint256[] calldata x, uint256 e) external returns (uint256) { + return uint256[](x[:e]).length; + } + function g(uint256[] calldata x, uint256 s, uint256 e, uint256 idx) external returns (uint256) { + return uint256[](x[s:e])[idx]; + } + function gg(uint256[] calldata x, uint256 s, uint256 e, uint256 idx) external returns (uint256) { + return x[s:e][idx]; + } + function gg_s_only(uint256[] calldata x, uint256 s, uint256 idx) external returns (uint256) { + return x[s:][idx]; + } + function gg_e_only(uint256[] calldata x, uint256 e, uint256 idx) external returns (uint256) { + return x[:e][idx]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256[],uint256,uint256): 0x60, 2, 4, 5, 1, 2, 3, 4, 5 -> 2 +// f(uint256[],uint256,uint256): 0x60, 2, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// f(uint256[],uint256,uint256): 0x60, 3, 3, 5, 1, 2, 3, 4, 5 -> 0 +// f(uint256[],uint256,uint256): 0x60, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE +// f(uint256[],uint256,uint256): 0x60, 0, 3, 5, 1, 2, 3, 4, 5 -> 3 +// f(uint256[],uint256,uint256,uint256,uint256): 0xA0, 1, 3, 1, 2, 5, 1, 2, 3, 4, 5 -> 1 +// f(uint256[],uint256,uint256,uint256,uint256): 0xA0, 1, 3, 1, 4, 5, 1, 2, 3, 4, 5 -> FAILURE +// f_s_only(uint256[],uint256): 0x40, 2, 5, 1, 2, 3, 4, 5 -> 3 +// f_s_only(uint256[],uint256): 0x40, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// f_e_only(uint256[],uint256): 0x40, 3, 5, 1, 2, 3, 4, 5 -> 3 +// f_e_only(uint256[],uint256): 0x40, 6, 5, 1, 2, 3, 4, 5 -> FAILURE +// g(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 1, 5, 1, 2, 3, 4, 5 -> 4 +// g(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE +// gg(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 1, 5, 1, 2, 3, 4, 5 -> 4 +// gg(uint256[],uint256,uint256,uint256): 0x80, 2, 4, 3, 5, 1, 2, 3, 4, 5 -> FAILURE From 4fcc33c5e5e527dc6e69e7eff7a83c2df8a4a8fa Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Sun, 15 Mar 2020 18:38:13 -0400 Subject: [PATCH 043/165] Remove byte-reinterpret conversion operator from vector_ref --- libsolutil/vector_ref.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolutil/vector_ref.h b/libsolutil/vector_ref.h index 3bb71f35e8de..46901a46e5c6 100644 --- a/libsolutil/vector_ref.h +++ b/libsolutil/vector_ref.h @@ -44,7 +44,6 @@ class vector_ref std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(T)); } - template explicit operator vector_ref() const { assert(m_count * sizeof(T) / sizeof(T2) * sizeof(T2) / sizeof(T) == m_count); return vector_ref(reinterpret_cast(m_data), m_count * sizeof(T) / sizeof(T2)); } operator vector_ref() const { return vector_ref(m_data, m_count); } T* data() const { return m_data; } From 151bc71f492de487180751329aece93fe902a722 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 9 Mar 2020 15:57:21 +0100 Subject: [PATCH 044/165] Add private-can-be-overridden bug to buglist --- docs/bugs.json | 8 ++++++ docs/bugs_by_version.json | 54 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/bugs.json b/docs/bugs.json index 66f1808abd79..388bd4b56e61 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -10,6 +10,14 @@ "yulOptimizer": true } }, + { + "name": "privateCanBeOverridden", + "summary": "Private methods can be overridden by inheriting contracts.", + "description": "While private methods of base contracts are not visible and cannot be called directly from the derived contract, it is still possible to declare a function of the same name and type and thus change the behaviour of the base contract's function.", + "introduced": "0.3.0", + "fixed": "0.5.17", + "severity": "low" + }, { "name": "YulOptimizerRedundantAssignmentBreakContinue0.5", "summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index dc32e2687d33..adee43296ce6 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -211,6 +211,7 @@ }, "0.3.0": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -232,6 +233,7 @@ }, "0.3.1": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -252,6 +254,7 @@ }, "0.3.2": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -272,6 +275,7 @@ }, "0.3.3": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -291,6 +295,7 @@ }, "0.3.4": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -310,6 +315,7 @@ }, "0.3.5": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -329,6 +335,7 @@ }, "0.3.6": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -346,6 +353,7 @@ }, "0.4.0": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -363,6 +371,7 @@ }, "0.4.1": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -380,6 +389,7 @@ }, "0.4.10": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -395,6 +405,7 @@ }, "0.4.11": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -409,6 +420,7 @@ }, "0.4.12": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -422,6 +434,7 @@ }, "0.4.13": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -435,6 +448,7 @@ }, "0.4.14": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -447,6 +461,7 @@ }, "0.4.15": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -458,6 +473,7 @@ }, "0.4.16": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -471,6 +487,7 @@ }, "0.4.17": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -485,6 +502,7 @@ }, "0.4.18": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -498,6 +516,7 @@ }, "0.4.19": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -512,6 +531,7 @@ }, "0.4.2": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -528,6 +548,7 @@ }, "0.4.20": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -542,6 +563,7 @@ }, "0.4.21": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -556,6 +578,7 @@ }, "0.4.22": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -570,6 +593,7 @@ }, "0.4.23": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -583,6 +607,7 @@ }, "0.4.24": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -596,6 +621,7 @@ }, "0.4.25": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -607,6 +633,7 @@ }, "0.4.26": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2" @@ -615,6 +642,7 @@ }, "0.4.3": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -630,6 +658,7 @@ }, "0.4.4": { "bugs": [ + "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -644,6 +673,7 @@ }, "0.4.5": { "bugs": [ + "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -660,6 +690,7 @@ }, "0.4.6": { "bugs": [ + "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -675,6 +706,7 @@ }, "0.4.7": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -690,6 +722,7 @@ }, "0.4.8": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -705,6 +738,7 @@ }, "0.4.9": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -720,6 +754,7 @@ }, "0.5.0": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -731,6 +766,7 @@ }, "0.5.1": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -742,6 +778,7 @@ }, "0.5.10": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers" ], @@ -749,24 +786,28 @@ }, "0.5.11": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-08-12" }, "0.5.12": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-10-01" }, "0.5.13": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-11-14" }, "0.5.14": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2LoopYulOptimizer" ], @@ -774,16 +815,20 @@ }, "0.5.15": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], "released": "2019-12-17" }, "0.5.16": { - "bugs": [], + "bugs": [ + "privateCanBeOverridden" + ], "released": "2020-01-02" }, "0.5.2": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -795,6 +840,7 @@ }, "0.5.3": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -806,6 +852,7 @@ }, "0.5.4": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -817,6 +864,7 @@ }, "0.5.5": { "bugs": [ + "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", "DynamicConstructorArgumentsClippedABIV2", @@ -830,6 +878,7 @@ }, "0.5.6": { "bugs": [ + "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -843,6 +892,7 @@ }, "0.5.7": { "bugs": [ + "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -854,6 +904,7 @@ }, "0.5.8": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", @@ -864,6 +915,7 @@ }, "0.5.9": { "bugs": [ + "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", From 4d99a54d05a8f4d080e24ef8e094dc9ae93d5ae5 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 16 Mar 2020 16:48:32 +0100 Subject: [PATCH 045/165] Fix broken yul-object link in docs --- docs/yul.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/yul.rst b/docs/yul.rst index 93bfe48a9f79..c6fb28986d22 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -111,7 +111,7 @@ Stand-Alone Usage ================= You can use Yul in its stand-alone form in the EVM dialect using the Solidity compiler. -This will use the `Yul object notation `_ so that it is possible to refer +This will use the :ref:`Yul object notation ` so that it is possible to refer to code as data to deploy contracts. This Yul mode is available for the commandline compiler (use ``--strict-assembly``) and for the :ref:`standard-json interface `: @@ -146,7 +146,7 @@ so you can e.g. use ``//`` and ``/* */`` to denote comments. There is one exception: Identifiers in Yul can contain dots: ``.``. Yul can specify "objects" that consist of code, data and sub-objects. -Please see `Yul Objects `_ below for details on that. +Please see :ref:`Yul Objects ` below for details on that. In this section, we are only concerned with the code part of such an object. This code part always consists of a curly-braces delimited block. Most tools support specifying just a code block From 1b63b8822e09d7be9c399b00b1c48f333dfa1ee0 Mon Sep 17 00:00:00 2001 From: gitpusha Date: Tue, 11 Feb 2020 10:32:33 +0100 Subject: [PATCH 046/165] Added note recommending to avoid relying on hardcoded gas values --- docs/types/value-types.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 9dae379124eb..a912534ac768 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -300,6 +300,11 @@ All three functions ``call``, ``delegatecall`` and ``staticcall`` are very low-l The ``gas`` option is available on all three methods, while the ``value`` option is not supported for ``delegatecall``. +.. note:: + It is best to avoid relying on hardcoded gas values in your smart contract code, + regardless of whether state is read from or written to, as this can have many pitfalls. + Also, access to gas might change in the future. + .. note:: All contracts can be converted to ``address`` type, so it is possible to query the balance of the current contract using ``address(this).balance``. From 9ef63a9789b38599eda4428cb5c4b47597b96a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:25:00 +0100 Subject: [PATCH 047/165] [yul-phaser] Program: Output operator for ErrorList - It does not seem universal enough to put it in liblangutil but in the scope of yul-phaser it's generic enough so I'm going to keep it together with Program. --- tools/yulPhaser/Program.cpp | 11 +++++++++++ tools/yulPhaser/Program.h | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index 42cc8bf61438..b4a6e444458a 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,16 @@ ostream& operator<<(ostream& _stream, Program const& _program); } +ostream& std::operator<<(ostream& _outputStream, ErrorList const& _errors) +{ + SourceReferenceFormatter formatter(_outputStream); + + for (auto const& error: _errors) + formatter.printErrorInformation(*error); + + return _outputStream; +} + Program::Program(Program const& program): m_ast(make_unique(get(ASTCopier{}(*program.m_ast)))), m_dialect{program.m_dialect}, diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index 5e240e98dc3f..c77ada9f2b40 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -41,6 +41,13 @@ struct Dialect; } +namespace std +{ + +std::ostream& operator<<(std::ostream& _outputStream, solidity::langutil::ErrorList const& _errors); + +} + namespace solidity::phaser { From 8ca0d90aae9fc0e2759ca3f8b1c5f31269a2c664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:33:46 +0100 Subject: [PATCH 048/165] [yul-phaser] Returning an ErrorList from Program::load() if program has errors and printing them in Phaser --- test/yulPhaser/FitnessMetrics.cpp | 2 +- test/yulPhaser/Program.cpp | 22 +++++++++--------- tools/yulPhaser/Phaser.cpp | 8 ++++++- tools/yulPhaser/Program.cpp | 38 ++++++++++++++++++++----------- tools/yulPhaser/Program.h | 9 +++++--- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 58561806dcba..ecb628c6be61 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -36,7 +36,7 @@ class FitnessMetricFixture protected: FitnessMetricFixture(): m_sourceStream(SampleSourceCode, ""), - m_program(Program::load(m_sourceStream)) {} + m_program(get(Program::load(m_sourceStream))) {} static constexpr char SampleSourceCode[] = "{\n" diff --git a/test/yulPhaser/Program.cpp b/test/yulPhaser/Program.cpp index 5c1d2a6e6c1d..5d4e012f39a8 100644 --- a/test/yulPhaser/Program.cpp +++ b/test/yulPhaser/Program.cpp @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(copy_constructor_should_make_deep_copy_of_ast) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); Program programCopy(program); @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(load_should_rewind_the_stream) CharStream sourceStream(sourceCode, current_test_case().p_name); sourceStream.setPosition(5); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(CodeSize::codeSize(program.ast()) == 2); } @@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(load_should_disambiguate) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. Block const& parentBlock = skipRedundantBlocks(program.ast()); @@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_function_grouping_and_hoisting) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(program.ast().statements.size() == 3); BOOST_TEST(holds_alternative(program.ast().statements[0])); @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_loop_init_rewriting) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. Block const& parentBlock = skipRedundantBlocks(program.ast()); @@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_parsed) string sourceCode("invalid program\n"); CharStream sourceStream(sourceCode, current_test_case().p_name); - BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); + BOOST_TEST(holds_alternative(Program::load(sourceStream))); } BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyzed) @@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyze ); CharStream sourceStream(sourceCode, current_test_case().p_name); - BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); + BOOST_TEST(holds_alternative(Program::load(sourceStream))); } BOOST_AUTO_TEST_CASE(optimise) @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(optimise) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); [[maybe_unused]] Block const& parentBlockBefore = skipRedundantBlocks(program.ast()); assert(parentBlockBefore.statements.size() == 2); @@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(output_operator) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); // NOTE: The snippet above was chosen so that the few optimisations applied automatically by load() // as of now do not change the code significantly. If that changes, you may have to update it. @@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(toJson) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); Json::Value parsingResult; string errors; @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(codeSize) "}\n" ); CharStream sourceStream(sourceCode, current_test_case().p_name); - auto program = Program::load(sourceStream); + Program program = get(Program::load(sourceStream)); BOOST_TEST(program.codeSize() == CodeSize::codeSizeIncludingFunctions(program.ast())); } diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 44fb9d130124..cc093c9c8057 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -125,7 +125,13 @@ ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_m Program ProgramFactory::build(Options const& _options) { CharStream sourceCode = loadSource(_options.inputFile); - return Program::load(sourceCode); + variant programOrErrors = Program::load(sourceCode); + if (holds_alternative(programOrErrors)) + { + cerr << get(programOrErrors) << endl; + assertThrow(false, InvalidProgram, "Failed to load program " + _options.inputFile); + } + return move(get(programOrErrors)); } CharStream ProgramFactory::loadSource(string const& _sourcePath) diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index b4a6e444458a..f6bda59bda55 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -17,11 +17,8 @@ #include -#include - #include #include -#include #include #include @@ -75,16 +72,29 @@ Program::Program(Program const& program): { } -Program Program::load(CharStream& _sourceCode) +variant Program::load(CharStream& _sourceCode) { // ASSUMPTION: parseSource() rewinds the stream on its own Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); - unique_ptr ast = parseSource(dialect, _sourceCode); - unique_ptr analysisInfo = analyzeAST(dialect, *ast); + + variant, ErrorList> astOrErrors = parseSource(dialect, _sourceCode); + if (holds_alternative(astOrErrors)) + return get(astOrErrors); + + variant, ErrorList> analysisInfoOrErrors = analyzeAST( + dialect, + *get>(astOrErrors) + ); + if (holds_alternative(analysisInfoOrErrors)) + return get(analysisInfoOrErrors); Program program( dialect, - disambiguateAST(dialect, *ast, *analysisInfo) + disambiguateAST( + dialect, + *get>(astOrErrors), + *get>(analysisInfoOrErrors) + ) ); program.optimise({ FunctionHoister::name, @@ -111,7 +121,7 @@ string Program::toJson() const return jsonPrettyPrint(serializedAst); } -unique_ptr Program::parseSource(Dialect const& _dialect, CharStream _source) +variant, ErrorList> Program::parseSource(Dialect const& _dialect, CharStream _source) { ErrorList errors; ErrorReporter errorReporter(errors); @@ -119,13 +129,14 @@ unique_ptr Program::parseSource(Dialect const& _dialect, CharStream _sour Parser parser(errorReporter, _dialect); unique_ptr ast = parser.parse(scanner, false); - assertThrow(ast != nullptr, InvalidProgram, "Error parsing source"); - assert(errorReporter.errors().empty()); + if (ast == nullptr) + return errors; + assert(errorReporter.errors().empty()); return ast; } -unique_ptr Program::analyzeAST(Dialect const& _dialect, Block const& _ast) +variant, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) { ErrorList errors; ErrorReporter errorReporter(errors); @@ -133,9 +144,10 @@ unique_ptr Program::analyzeAST(Dialect const& _dialect, Block c AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect); bool analysisSuccessful = analyzer.analyze(_ast); - assertThrow(analysisSuccessful, InvalidProgram, "Error analyzing source"); - assert(errorReporter.errors().empty()); + if (!analysisSuccessful) + return errors; + assert(errorReporter.errors().empty()); return analysisInfo; } diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index c77ada9f2b40..6da9751b9647 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -20,10 +20,13 @@ #include #include +#include + #include #include #include #include +#include #include namespace solidity::langutil @@ -72,7 +75,7 @@ class Program Program operator=(Program const& program) = delete; Program operator=(Program&& program) = delete; - static Program load(langutil::CharStream& _sourceCode); + static std::variant load(langutil::CharStream& _sourceCode); void optimise(std::vector const& _optimisationSteps); size_t codeSize() const { return computeCodeSize(*m_ast); } @@ -91,11 +94,11 @@ class Program m_nameDispenser(_dialect, *m_ast, {}) {} - static std::unique_ptr parseSource( + static std::variant, langutil::ErrorList> parseSource( yul::Dialect const& _dialect, langutil::CharStream _source ); - static std::unique_ptr analyzeAST( + static std::variant, langutil::ErrorList> analyzeAST( yul::Dialect const& _dialect, yul::Block const& _ast ); From c7051e13863a1fdd01c9160396bf8a74a7c56d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 5 Mar 2020 04:44:32 +0100 Subject: [PATCH 049/165] [yul-phaser] Program: Explicitly return variants values - Otherwise the code fails to build with on GCC 7.4.0 on Ubuntu in the CI pipeline --- tools/yulPhaser/Program.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index f6bda59bda55..c397cd1f49b0 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -133,7 +133,7 @@ variant, ErrorList> Program::parseSource(Dialect const& _diale return errors; assert(errorReporter.errors().empty()); - return ast; + return variant, ErrorList>(move(ast)); } variant, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) @@ -148,7 +148,7 @@ variant, ErrorList> Program::analyzeAST(Dialect cons return errors; assert(errorReporter.errors().empty()); - return analysisInfo; + return variant, ErrorList>(move(analysisInfo)); } unique_ptr Program::disambiguateAST( From 4e90c598b3d5cb665929ccb11dcd49b7abbb0ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:30:19 +0100 Subject: [PATCH 050/165] [yul-phaser] main: Dealing with uncaught exceptions --- tools/yulPhaser/main.cpp | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index eecaf6d3c8fc..0b56f016545b 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include int main(int argc, char** argv) @@ -28,7 +30,51 @@ int main(int argc, char** argv) } catch (solidity::phaser::InvalidProgram const& exception) { + // Error in the input data. One of the provided programs contains errors and could not be loaded. + // Handle it and exit. + + std::cerr << std::endl; std::cerr << "ERROR: " << exception.what() << std::endl; return 1; } + catch (solidity::util::Exception const& exception) + { + // Something's seriously wrong. Probably a bug in the program or a missing handler (which + // is really also a bug). The exception should have been handled gracefully by this point + // if it's something that can happen in normal usage. E.g. an error in the input or a + // failure of some part of the system that's outside of control of the application (disk, + // network, etc.). The bug should be reported and investigated so our job here is just to + // provide as much useful information about it as possible. + + std::cerr << std::endl; + std::cerr << "UNCAUGHT EXCEPTION!" << std::endl; + + // We can print some useful diagnostic info for this particular exception type. + std::cerr << "Location: " << exception.lineInfo() << std::endl; + + char const* const* function = boost::get_error_info(exception); + if (function != nullptr) + std::cerr << "Function: " << *function << std::endl; + + // Let it crash. The terminate() will print some more stuff useful for debugging like + // what() and the actual exception type. + throw; + } + catch (std::exception const&) + { + // Again, probably a bug but this time it's just plain std::exception so there's no point + // in doing anything special. terminate() will do an adequate job. + std::cerr << std::endl; + std::cerr << "UNCAUGHT EXCEPTION!" << std::endl; + throw; + } + catch (...) + { + // Some people don't believe these exist. + // I have no idea what this is and it's flying towards me so technically speaking it's an + // unidentified flying object. + std::cerr << std::endl; + std::cerr << "UFO SPOTTED!" << std::endl; + throw; + } } From 53803801f7274b2036e47b2c7f1daabb9f9f9d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:47:00 +0100 Subject: [PATCH 051/165] [yul-phaser] Move handling of boost::program_options::error to the top-level exception handler --- tools/yulPhaser/Phaser.cpp | 14 +++----------- tools/yulPhaser/main.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index cc093c9c8057..87bbb0ebad73 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -205,17 +205,9 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg po::variables_map arguments; po::notify(arguments); - try - { - po::command_line_parser parser(_argc, _argv); - parser.options(keywordDescription).positional(positionalDescription); - po::store(parser.run(), arguments); - } - catch (po::error const & _exception) - { - cerr << _exception.what() << endl; - return {1, move(arguments)}; - } + po::command_line_parser parser(_argc, _argv); + parser.options(keywordDescription).positional(positionalDescription); + po::store(parser.run(), arguments); if (arguments.count("help") > 0) { diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 0b56f016545b..1cfd310b7f4d 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -28,6 +28,14 @@ int main(int argc, char** argv) { return solidity::phaser::Phaser::main(argc, argv); } + catch (boost::program_options::error const& exception) + { + // Bad input data. Invalid command-line parameters. + + std::cerr << std::endl; + std::cerr << "ERROR: " << exception.what() << std::endl; + return 1; + } catch (solidity::phaser::InvalidProgram const& exception) { // Error in the input data. One of the provided programs contains errors and could not be loaded. From f05a07d0ccce869f59b2cb921a52a6f539d84c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:48:20 +0100 Subject: [PATCH 052/165] [yul-phaser] Create BadInput exception hierarchy and make exceptions used by Phaser more specific --- tools/yulPhaser/Exceptions.h | 5 ++++- tools/yulPhaser/Phaser.cpp | 7 ++----- tools/yulPhaser/main.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/yulPhaser/Exceptions.h b/tools/yulPhaser/Exceptions.h index ae75d19ef9c6..1f675a9ef5d2 100644 --- a/tools/yulPhaser/Exceptions.h +++ b/tools/yulPhaser/Exceptions.h @@ -22,6 +22,9 @@ namespace solidity::phaser { -struct InvalidProgram: virtual util::Exception {}; +struct BadInput: virtual util::Exception {}; +struct InvalidProgram: virtual BadInput {}; +struct NoInputFiles: virtual BadInput {}; +struct MissingFile: virtual BadInput {}; } diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 87bbb0ebad73..4c2aff0713ef 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -136,7 +136,7 @@ Program ProgramFactory::build(Options const& _options) CharStream ProgramFactory::loadSource(string const& _sourcePath) { - assertThrow(boost::filesystem::exists(_sourcePath), InvalidProgram, "Source file does not exist"); + assertThrow(boost::filesystem::exists(_sourcePath), MissingFile, "Source file does not exist: " + _sourcePath); string sourceCode = readFileAsString(_sourcePath); return CharStream(sourceCode, _sourcePath); @@ -216,10 +216,7 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg } if (arguments.count("input-file") == 0) - { - cerr << "Missing argument: input-file." << endl; - return {1, move(arguments)}; - } + assertThrow(false, NoInputFiles, "Missing argument: input-file."); return {0, arguments}; } diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index 1cfd310b7f4d..a567e355a039 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -36,10 +36,10 @@ int main(int argc, char** argv) std::cerr << "ERROR: " << exception.what() << std::endl; return 1; } - catch (solidity::phaser::InvalidProgram const& exception) + catch (solidity::phaser::BadInput const& exception) { - // Error in the input data. One of the provided programs contains errors and could not be loaded. - // Handle it and exit. + // Bad input data. Syntax errors in the input program, semantic errors in command-line + // parameters, etc. std::cerr << std::endl; std::cerr << "ERROR: " << exception.what() << std::endl; From d86b5019dce7b1dc38869231711d769e6f9f6957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:54:05 +0100 Subject: [PATCH 053/165] [yul-phaser] Phaser: Returning exit code 0 instead of 2 when --help is requested - I don't think we really need to discern it from normal operation. It's what user requested so it's a success. --- tools/yulPhaser/Phaser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 4c2aff0713ef..6a7e7a88fa0f 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -212,7 +212,7 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg if (arguments.count("help") > 0) { cout << keywordDescription << endl; - return {2, move(arguments)}; + return {0, move(arguments)}; } if (arguments.count("input-file") == 0) From 760e7c3cc5b2b686ae2908e4493f3117592ba49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 03:58:26 +0100 Subject: [PATCH 054/165] [yul-phaser] Don't return exit code from Phaser::main() and just assume 0 if it does not throw. --- tools/yulPhaser/Phaser.cpp | 19 +++++++++---------- tools/yulPhaser/Phaser.h | 11 +++-------- tools/yulPhaser/main.cpp | 3 ++- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 6a7e7a88fa0f..5f0e3d87b1be 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -142,16 +142,15 @@ CharStream ProgramFactory::loadSource(string const& _sourcePath) return CharStream(sourceCode, _sourcePath); } -int Phaser::main(int _argc, char** _argv) +void Phaser::main(int _argc, char** _argv) { - CommandLineParsingResult parsingResult = parseCommandLine(_argc, _argv); - if (parsingResult.exitCode != 0) - return parsingResult.exitCode; + optional arguments = parseCommandLine(_argc, _argv); + if (!arguments.has_value()) + return; - initialiseRNG(parsingResult.arguments); + initialiseRNG(arguments.value()); - runAlgorithm(parsingResult.arguments); - return 0; + runAlgorithm(arguments.value()); } Phaser::CommandLineDescription Phaser::buildCommandLineDescription() @@ -198,7 +197,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() return {keywordDescription, positionalDescription}; } -Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _argv) +optional Phaser::parseCommandLine(int _argc, char** _argv) { auto [keywordDescription, positionalDescription] = buildCommandLineDescription(); @@ -212,13 +211,13 @@ Phaser::CommandLineParsingResult Phaser::parseCommandLine(int _argc, char** _arg if (arguments.count("help") > 0) { cout << keywordDescription << endl; - return {0, move(arguments)}; + return nullopt; } if (arguments.count("input-file") == 0) assertThrow(false, NoInputFiles, "Missing argument: input-file."); - return {0, arguments}; + return arguments; } void Phaser::initialiseRNG(po::variables_map const& _arguments) diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 75025557691d..9ac6f81f02c8 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -128,7 +129,7 @@ class ProgramFactory class Phaser { public: - static int main(int argc, char** argv); + static void main(int argc, char** argv); private: struct CommandLineDescription @@ -137,14 +138,8 @@ class Phaser boost::program_options::positional_options_description positionalDescription; }; - struct CommandLineParsingResult - { - int exitCode; - boost::program_options::variables_map arguments; - }; - static CommandLineDescription buildCommandLineDescription(); - static CommandLineParsingResult parseCommandLine(int _argc, char** _argv); + static std::optional parseCommandLine(int _argc, char** _argv); static void initialiseRNG(boost::program_options::variables_map const& _arguments); static void runAlgorithm(boost::program_options::variables_map const& _arguments); diff --git a/tools/yulPhaser/main.cpp b/tools/yulPhaser/main.cpp index a567e355a039..d0c00fcdace1 100644 --- a/tools/yulPhaser/main.cpp +++ b/tools/yulPhaser/main.cpp @@ -26,7 +26,8 @@ int main(int argc, char** argv) { try { - return solidity::phaser::Phaser::main(argc, argv); + solidity::phaser::Phaser::main(argc, argv); + return 0; } catch (boost::program_options::error const& exception) { From 66783c30ced159b1149e5f02547923e16002ceea Mon Sep 17 00:00:00 2001 From: a3d4 Date: Fri, 6 Mar 2020 01:22:51 +0100 Subject: [PATCH 055/165] Introduced TestCaseReader. --- libsolidity/interface/DebugSettings.h | 2 +- test/CMakeLists.txt | 2 + test/CommonSyntaxTest.cpp | 14 +-- test/TestCase.cpp | 124 ++---------------- test/TestCase.h | 33 ++--- test/TestCaseReader.cpp | 174 ++++++++++++++++++++++++++ test/TestCaseReader.h | 61 +++++++++ test/boostTest.cpp | 1 - test/libsolidity/ABIJsonTest.cpp | 12 +- test/libsolidity/GasTest.cpp | 35 ++---- test/libsolidity/SMTCheckerTest.cpp | 25 ++-- test/libsolidity/SemanticTest.cpp | 50 +++----- test/libsolidity/SemanticTest.h | 1 + test/libsolidity/SyntaxTest.cpp | 15 +-- test/libyul/EwasmTranslationTest.cpp | 14 +-- test/libyul/FunctionSideEffects.cpp | 12 +- test/libyul/ObjectCompilerTest.cpp | 21 +--- test/libyul/SyntaxTest.cpp | 20 +-- test/libyul/SyntaxTest.h | 10 +- test/libyul/YulInterpreterTest.cpp | 14 +-- test/libyul/YulOptimizerTest.cpp | 51 +++----- test/libyul/YulOptimizerTest.h | 1 + test/tools/CMakeLists.txt | 1 + test/tools/isoltest.cpp | 1 - 24 files changed, 348 insertions(+), 346 deletions(-) create mode 100644 test/TestCaseReader.cpp create mode 100644 test/TestCaseReader.h diff --git a/libsolidity/interface/DebugSettings.h b/libsolidity/interface/DebugSettings.h index 67c6d88109b8..34818889c953 100644 --- a/libsolidity/interface/DebugSettings.h +++ b/libsolidity/interface/DebugSettings.h @@ -54,7 +54,7 @@ inline std::optional revertStringsFromString(std::string const& _ for (auto i: {RevertStrings::Default, RevertStrings::Strip, RevertStrings::Debug, RevertStrings::VerboseDebug}) if (revertStringsToString(i) == _str) return i; - return {}; + return std::nullopt; } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fa9127e7223f..00c682416548 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,6 +13,8 @@ set(sources Metadata.h TestCase.cpp TestCase.h + TestCaseReader.cpp + TestCaseReader.h ) detect_stray_source_files("${sources}" ".") diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 6d72ce010ff3..ebc80dc2f128 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -56,16 +56,12 @@ int parseUnsignedInteger(string::iterator& _it, string::iterator _end) } -CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion) +CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): + EVMVersionRestrictedTestCase(_filename), + m_evmVersion(_evmVersion) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_sources = parseSourcesAndSettings(file); - - m_expectations = parseExpectations(file); + m_sources = m_reader.sources(); + m_expectations = parseExpectations(m_reader.stream()); } TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 6b0a16e27cd3..8b2afc7802f9 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -18,16 +18,9 @@ #include #include -#include - -#include -#include #include -#include -#include #include - #include using namespace std; @@ -37,11 +30,12 @@ using namespace solidity::frontend::test; void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool) { - if (m_validatedSettings.empty()) + auto& settings = m_reader.settings(); + if (settings.empty()) return; _stream << _linePrefix << "// ====" << endl; - for (auto const& setting: m_validatedSettings) + for (auto const& setting: settings) _stream << _linePrefix << "// " << setting.first << ": " << setting.second << endl; } @@ -53,108 +47,12 @@ bool TestCase::isTestFilename(boost::filesystem::path const& _filename) !boost::starts_with(_filename.string(), "."); } -void TestCase::validateSettings() -{ - if (!m_settings.empty()) - throw runtime_error( - "Unknown setting(s): " + - util::joinHumanReadable(m_settings | boost::adaptors::map_keys) - ); -} - bool TestCase::shouldRun() { + m_reader.ensureAllSettingsRead(); return m_shouldRun; } -pair, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream) -{ - map sources; - string currentSourceName; - string currentSource; - string line; - size_t lineNumber = 1; - static string const sourceDelimiterStart("==== Source:"); - static string const sourceDelimiterEnd("===="); - static string const comment("// "); - static string const settingsDelimiter("// ===="); - static string const delimiter("// ----"); - bool sourcePart = true; - while (getline(_stream, line)) - { - lineNumber++; - - if (boost::algorithm::starts_with(line, delimiter)) - break; - else if (boost::algorithm::starts_with(line, settingsDelimiter)) - sourcePart = false; - else if (sourcePart) - { - if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd)) - { - if (!(currentSourceName.empty() && currentSource.empty())) - sources[currentSourceName] = std::move(currentSource); - currentSource = {}; - currentSourceName = boost::trim_copy(line.substr( - sourceDelimiterStart.size(), - line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size() - )); - if (sources.count(currentSourceName)) - throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."); - } - else - currentSource += line + "\n"; - } - else if (boost::algorithm::starts_with(line, comment)) - { - size_t colon = line.find(':'); - if (colon == string::npos) - throw runtime_error(string("Expected \":\" inside setting.")); - string key = line.substr(comment.size(), colon - comment.size()); - string value = line.substr(colon + 1); - boost::algorithm::trim(key); - boost::algorithm::trim(value); - m_settings[key] = value; - } - else - throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); - } - sources[currentSourceName] = currentSource; - return {sources, lineNumber}; -} - -map TestCase::parseSourcesAndSettings(istream& _stream) -{ - return get<0>(parseSourcesAndSettingsWithLineNumbers(_stream)); -} - -pair TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream) -{ - auto [sourceMap, lineOffset] = parseSourcesAndSettingsWithLineNumbers(_stream); - if (sourceMap.size() != 1) - BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); - return {std::move(sourceMap.begin()->second), lineOffset}; -} - -string TestCase::parseSourceAndSettings(istream& _stream) -{ - return parseSourceAndSettingsWithLineNumbers(_stream).first; -} - -string TestCase::parseSimpleExpectations(std::istream& _file) -{ - string result; - string line; - while (getline(_file, line)) - if (boost::algorithm::starts_with(line, "// ")) - result += line.substr(3) + "\n"; - else if (line == "//") - result += "\n"; - else - BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \".")); - return result; -} - void TestCase::expect(string::iterator& _it, string::iterator _end, string::value_type _c) { if (_it == _end || *_it != _c) @@ -162,19 +60,13 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu ++_it; } -void EVMVersionRestrictedTestCase::validateSettings() +EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename): + TestCase(_filename) { - if (!m_settings.count("EVMVersion")) + if (!m_reader.hasSetting("EVMVersion")) return; - string versionString = m_settings["EVMVersion"]; - m_validatedSettings["EVMVersion"] = versionString; - m_settings.erase("EVMVersion"); - - TestCase::validateSettings(); - - if (versionString.empty()) - return; + string versionString = m_reader.stringSetting("EVMVersion", ""); string comparator; size_t versionBegin = 0; diff --git a/test/TestCase.h b/test/TestCase.h index d6afff8b8262..b4e7e3972fc4 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -17,16 +17,13 @@ #pragma once +#include + #include #include -#include -#include -#include #include -#include -#include namespace solidity::frontend::test { @@ -68,23 +65,19 @@ class TestCase static bool isTestFilename(boost::filesystem::path const& _filename); - /// Validates the settings, i.e. moves them from m_settings to m_validatedSettings. - /// Throws a runtime exception if any setting is left at this class (i.e. unknown setting). - virtual void validateSettings(); - /// Returns true, if the test case is supported in the current environment and false /// otherwise which causes this test to be skipped. /// This might check e.g. for restrictions on the EVM version. + /// The function throws an exception if there are unread settings. bool shouldRun(); protected: - std::pair, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file); - std::map parseSourcesAndSettings(std::istream& _file); - std::pair parseSourceAndSettingsWithLineNumbers(std::istream& _file); - std::string parseSourceAndSettings(std::istream& _file); - static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c); + // Used by ASTJSONTest, the only TestCase class with a custom parser of the test files. + TestCase() = default; + + TestCase(std::string const& _filename): m_reader(_filename) {} - static std::string parseSimpleExpectations(std::istream& _file); + static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c); template static void skipWhitespace(IteratorType& _it, IteratorType _end) @@ -100,18 +93,14 @@ class TestCase ++_it; } - /// Parsed settings. - std::map m_settings; - /// Updated settings after validation. - std::map m_validatedSettings; - + TestCaseReader m_reader; bool m_shouldRun = true; }; class EVMVersionRestrictedTestCase: public TestCase { -public: - void validateSettings() override; +protected: + EVMVersionRestrictedTestCase(std::string const& _filename); }; } diff --git a/test/TestCaseReader.cpp b/test/TestCaseReader.cpp new file mode 100644 index 000000000000..2b7e201af9f0 --- /dev/null +++ b/test/TestCaseReader.cpp @@ -0,0 +1,174 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace solidity::frontend::test; + +TestCaseReader::TestCaseReader(string const& _filename): + m_file(_filename) +{ + if (!m_file) + BOOST_THROW_EXCEPTION(runtime_error("Cannot open file: \"" + _filename + "\".")); + m_file.exceptions(ios::badbit); + + tie(m_sources, m_lineNumber) = parseSourcesAndSettingsWithLineNumber(m_file); + m_unreadSettings = m_settings; +} + +string const& TestCaseReader::source() +{ + if (m_sources.size() != 1) + BOOST_THROW_EXCEPTION(runtime_error("Expected single source definition, but got multiple sources.")); + return m_sources.begin()->second; +} + +string TestCaseReader::simpleExpectations() +{ + return parseSimpleExpectations(m_file); +} + +bool TestCaseReader::hasSetting(std::string const& _name) const +{ + return m_settings.count(_name) != 0; +} + +bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue) +{ + if (!hasSetting(_name)) + return _defaultValue; + + m_unreadSettings.erase(_name); + string value = m_settings.at(_name); + if (value == "false") + return false; + if (value == "true") + return true; + + BOOST_THROW_EXCEPTION(runtime_error("Invalid Boolean value: " + value + ".")); +} + +size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue) +{ + if (!hasSetting(_name)) + return _defaultValue; + + m_unreadSettings.erase(_name); + + static_assert(sizeof(unsigned long) <= sizeof(size_t)); + return stoul(m_settings.at(_name)); +} + +string TestCaseReader::stringSetting(string const& _name, string const& _defaultValue) +{ + if (!hasSetting(_name)) + return _defaultValue; + + m_unreadSettings.erase(_name); + return m_settings.at(_name); +} + +void TestCaseReader::setSetting(std::string const& _name, std::string const& _value) +{ + m_settings[_name] = _value; +} + +void TestCaseReader::ensureAllSettingsRead() const +{ + if (!m_unreadSettings.empty()) + throw runtime_error( + "Unknown setting(s): " + + util::joinHumanReadable(m_unreadSettings | boost::adaptors::map_keys) + ); +} + +pair, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream) +{ + map sources; + string currentSourceName; + string currentSource; + string line; + size_t lineNumber = 1; + static string const sourceDelimiterStart("==== Source:"); + static string const sourceDelimiterEnd("===="); + static string const comment("// "); + static string const settingsDelimiter("// ===="); + static string const delimiter("// ----"); + bool sourcePart = true; + while (getline(_stream, line)) + { + lineNumber++; + + if (boost::algorithm::starts_with(line, delimiter)) + break; + else if (boost::algorithm::starts_with(line, settingsDelimiter)) + sourcePart = false; + else if (sourcePart) + { + if (boost::algorithm::starts_with(line, sourceDelimiterStart) && boost::algorithm::ends_with(line, sourceDelimiterEnd)) + { + if (!(currentSourceName.empty() && currentSource.empty())) + sources[currentSourceName] = std::move(currentSource); + currentSource = {}; + currentSourceName = boost::trim_copy(line.substr( + sourceDelimiterStart.size(), + line.size() - sourceDelimiterEnd.size() - sourceDelimiterStart.size() + )); + if (sources.count(currentSourceName)) + throw runtime_error("Multiple definitions of test source \"" + currentSourceName + "\"."); + } + else + currentSource += line + "\n"; + } + else if (boost::algorithm::starts_with(line, comment)) + { + size_t colon = line.find(':'); + if (colon == string::npos) + throw runtime_error(string("Expected \":\" inside setting.")); + string key = line.substr(comment.size(), colon - comment.size()); + string value = line.substr(colon + 1); + boost::algorithm::trim(key); + boost::algorithm::trim(value); + m_settings[key] = value; + } + else + throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); + } + sources[currentSourceName] = currentSource; + return { sources, lineNumber }; +} + +string TestCaseReader::parseSimpleExpectations(istream& _file) +{ + string result; + string line; + while (getline(_file, line)) + if (boost::algorithm::starts_with(line, "// ")) + result += line.substr(3) + "\n"; + else if (line == "//") + result += "\n"; + else + BOOST_THROW_EXCEPTION(runtime_error("Test expectations must start with \"// \".")); + return result; +} diff --git a/test/TestCaseReader.h b/test/TestCaseReader.h new file mode 100644 index 000000000000..055b355b7cbc --- /dev/null +++ b/test/TestCaseReader.h @@ -0,0 +1,61 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include +#include +#include + +#pragma once + +namespace solidity::frontend::test +{ +/** + * A reader for test case data file, which parses source, settings and (optionally) simple expectations. + */ +class TestCaseReader +{ +public: + TestCaseReader() = default; + explicit TestCaseReader(std::string const& _filename); + + std::map const& sources() { return m_sources; } + std::string const& source(); + std::size_t lineNumber() { return m_lineNumber; } + std::map const& settings() { return m_settings; } + std::ifstream& stream() { return m_file; } + + std::string simpleExpectations(); + + bool hasSetting(std::string const& _name) const; + bool boolSetting(std::string const& _name, bool _defaultValue); + size_t sizetSetting(std::string const& _name, size_t _defaultValue); + std::string stringSetting(std::string const& _name, std::string const& _defaultValue); + void setSetting(std::string const& _name, std::string const& _value); + + void ensureAllSettingsRead() const; + +private: + std::pair, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file); + static std::string parseSimpleExpectations(std::istream& _file); + + std::ifstream m_file; + std::map m_sources; + std::size_t m_lineNumber = 0; + std::map m_settings; + std::map m_unreadSettings; ///< tracks which settings are left unread +}; +} diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 3137a50854f5..5a76a3f18886 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -94,7 +94,6 @@ int registerTests( { stringstream errorStream; auto testCase = _testCaseCreator(config); - testCase->validateSettings(); if (testCase->shouldRun()) switch (testCase->run(errorStream)) { diff --git a/test/libsolidity/ABIJsonTest.cpp b/test/libsolidity/ABIJsonTest.cpp index 1da0193ab42d..e7a0cce6dd7c 100644 --- a/test/libsolidity/ABIJsonTest.cpp +++ b/test/libsolidity/ABIJsonTest.cpp @@ -36,15 +36,11 @@ using namespace solidity::util; using namespace solidity::frontend; using namespace solidity::frontend::test; -ABIJsonTest::ABIJsonTest(string const& _filename) +ABIJsonTest::ABIJsonTest(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult ABIJsonTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index b1b0d56f23f7..694839b99ef3 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -36,35 +36,14 @@ using namespace std; namespace fs = boost::filesystem; using namespace boost::unit_test; -GasTest::GasTest(string const& _filename) +GasTest::GasTest(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - - if (m_settings.count("optimize")) - { - m_optimise = true; - m_validatedSettings["optimize"] = "true"; - m_settings.erase("optimize"); - } - if (m_settings.count("optimize-yul")) - { - m_optimiseYul = true; - m_validatedSettings["optimize-yul"] = "true"; - m_settings.erase("optimize-yul"); - } - if (m_settings.count("optimize-runs")) - { - m_optimiseRuns = stoul(m_settings["optimize-runs"]); - m_validatedSettings["optimize-runs"] = m_settings["optimize-runs"]; - m_settings.erase("optimize-runs"); - } - - parseExpectations(file); + m_source = m_reader.source(); + m_optimise = m_reader.boolSetting("optimize", false); + m_optimiseYul = m_reader.boolSetting("optimize-yul", false); + m_optimiseRuns = m_reader.sizetSetting("optimize-runs", 200); + parseExpectations(m_reader.stream()); } void GasTest::parseExpectations(std::istream& _stream) diff --git a/test/libsolidity/SMTCheckerTest.cpp b/test/libsolidity/SMTCheckerTest.cpp index 912349182784..f0bfed8d4b61 100644 --- a/test/libsolidity/SMTCheckerTest.cpp +++ b/test/libsolidity/SMTCheckerTest.cpp @@ -28,22 +28,17 @@ using namespace solidity::frontend::test; SMTCheckerTest::SMTCheckerTest(string const& _filename, langutil::EVMVersion _evmVersion): SyntaxTest(_filename, _evmVersion) { - if (m_settings.count("SMTSolvers")) - { - auto const& choice = m_settings.at("SMTSolvers"); - if (choice == "any") - m_enabledSolvers = smt::SMTSolverChoice::All(); - else if (choice == "z3") - m_enabledSolvers = smt::SMTSolverChoice::Z3(); - else if (choice == "cvc4") - m_enabledSolvers = smt::SMTSolverChoice::CVC4(); - else if (choice == "none") - m_enabledSolvers = smt::SMTSolverChoice::None(); - else - BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice.")); - } - else + auto const& choice = m_reader.stringSetting("SMTSolvers", "any"); + if (choice == "any") m_enabledSolvers = smt::SMTSolverChoice::All(); + else if (choice == "z3") + m_enabledSolvers = smt::SMTSolverChoice::Z3(); + else if (choice == "cvc4") + m_enabledSolvers = smt::SMTSolverChoice::CVC4(); + else if (choice == "none") + m_enabledSolvers = smt::SMTSolverChoice::None(); + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice.")); auto available = ModelChecker::availableSolvers(); if (!available.z3) diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 97c83a3e5eee..8b5112e1263b 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -37,59 +37,39 @@ namespace fs = boost::filesystem; SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion): - SolidityExecutionFramework(_evmVersion) + SolidityExecutionFramework(_evmVersion), + EVMVersionRestrictedTestCase(_filename) { - ifstream file(_filename); - soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); - file.exceptions(ios::badbit); + m_source = m_reader.source(); + m_lineOffset = m_reader.lineNumber(); - std::tie(m_source, m_lineOffset) = parseSourceAndSettingsWithLineNumbers(file); - - if (m_settings.count("compileViaYul")) + if (m_reader.hasSetting("compileViaYul")) { - if (m_settings["compileViaYul"] == "also") + string choice = m_reader.stringSetting("compileViaYul", ""); + if (choice == "also") { - m_validatedSettings["compileViaYul"] = m_settings["compileViaYul"]; m_runWithYul = true; m_runWithoutYul = true; } else { - m_validatedSettings["compileViaYul"] = "only"; + m_reader.setSetting("compileViaYul", "only"); m_runWithYul = true; m_runWithoutYul = false; } - m_settings.erase("compileViaYul"); - } - if (m_settings.count("ABIEncoderV1Only")) - { - if (m_settings["ABIEncoderV1Only"] == "true") - { - m_validatedSettings["ABIEncoderV1Only"] = "true"; - m_runWithABIEncoderV1Only = true; - } - m_settings.erase("ABIEncoderV1Only"); } + m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false); if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2) m_shouldRun = false; - if (m_settings.count("revertStrings")) - { - auto revertStrings = revertStringsFromString(m_settings["revertStrings"]); - if (revertStrings) - m_revertStrings = *revertStrings; - m_validatedSettings["revertStrings"] = revertStringsToString(m_revertStrings); - m_settings.erase("revertStrings"); - } + auto revertStrings = revertStringsFromString(m_reader.stringSetting("revertStrings", "default")); + soltestAssert(revertStrings, "Invalid revertStrings setting."); + m_revertStrings = revertStrings.value(); - if (m_settings.count("allowNonExistingFunctions")) - { - m_validatedSettings["allowNonExistingFunctions"] = true; - m_settings.erase("allowNonExistingFunctions"); - } + m_allowNonExistingFunctions = m_reader.boolSetting("allowNonExistingFunctions", false); - parseExpectations(file); + parseExpectations(m_reader.stream()); soltestAssert(!m_tests.empty(), "No tests specified in " + _filename); } @@ -152,7 +132,7 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref else { soltestAssert( - m_validatedSettings.count("allowNonExistingFunctions") || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), + m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature), "The function " + test.call().signature + " is not known to the compiler" ); diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 0ea486cad327..94c29e193efd 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -65,6 +65,7 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict bool m_runWithYul = false; bool m_runWithoutYul = true; bool m_runWithABIEncoderV1Only = false; + bool m_allowNonExistingFunctions = false; }; } diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 1938cfe86a33..031a6085f939 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -37,20 +37,7 @@ namespace fs = boost::filesystem; SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): CommonSyntaxTest(_filename, _evmVersion) { - if (m_settings.count("optimize-yul")) - { - if (m_settings["optimize-yul"] == "true") - { - m_validatedSettings["optimize-yul"] = "true"; - m_settings.erase("optimize-yul"); - } - else if (m_settings["optimize-yul"] == "false") - { - m_validatedSettings["optimize-yul"] = "false"; - m_settings.erase("optimize-yul"); - m_optimiseYul = false; - } - } + m_optimiseYul = m_reader.boolSetting("optimize-yul", true); m_parserErrorRecovery = _parserErrorRecovery; } diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index fdee56bda223..a545b6124f5b 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -48,17 +48,11 @@ using namespace solidity::frontend::test; using namespace std; -EwasmTranslationTest::EwasmTranslationTest(string const& _filename) +EwasmTranslationTest::EwasmTranslationTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult EwasmTranslationTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/FunctionSideEffects.cpp b/test/libyul/FunctionSideEffects.cpp index 2d74d5501a97..db3a39df00f6 100644 --- a/test/libyul/FunctionSideEffects.cpp +++ b/test/libyul/FunctionSideEffects.cpp @@ -60,15 +60,11 @@ string toString(SideEffects const& _sideEffects) } } -FunctionSideEffects::FunctionSideEffects(string const& _filename) +FunctionSideEffects::FunctionSideEffects(string const& _filename): + TestCase(_filename) { - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test input: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult FunctionSideEffects::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index f1b284042e9f..9dd589748f80 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -38,23 +38,12 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -ObjectCompilerTest::ObjectCompilerTest(string const& _filename) +ObjectCompilerTest::ObjectCompilerTest(string const& _filename): + TestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - if (m_settings.count("optimize")) - { - m_optimize = true; - m_validatedSettings["optimize"] = "true"; - m_settings.erase("optimize"); - } - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_optimize = m_reader.boolSetting("optimize", false); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index 75e38c844d57..8e5862b43f40 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -70,9 +70,7 @@ vector validDialectNames() void SyntaxTest::parseAndAnalyze() { - string dialectName = m_validatedSettings.count("dialect") ? m_validatedSettings["dialect"] : "evmTyped"; - - yul::Dialect const& dialect = validDialects.at(dialectName)(m_evmVersion); + yul::Dialect const& dialect = validDialects.at(m_dialectName)(m_evmVersion); if (m_sources.size() != 1) BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."}); @@ -114,21 +112,15 @@ void SyntaxTest::parseAndAnalyze() } -void SyntaxTest::validateSettings() +SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): + CommonSyntaxTest(_filename, _evmVersion) { - CommonSyntaxTest::validateSettings(); - - if (!m_settings.count("dialect")) - return; - - string const dialect = m_settings["dialect"]; - m_validatedSettings["dialect"] = dialect; - m_settings.erase("dialect"); + m_dialectName = m_reader.stringSetting("dialect", "evmTyped"); - if (!validDialects.count(dialect)) + if (!validDialects.count(m_dialectName)) BOOST_THROW_EXCEPTION(runtime_error{ "Invalid Dialect \"" + - dialect + + m_dialectName + "\". Valid dialects are " + joinHumanReadable(validDialectNames(), ", ", " and ") + "." diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h index 087a6326cab7..8b4c24bd83fa 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -36,15 +36,13 @@ class SyntaxTest: public solidity::test::CommonSyntaxTest { return std::make_unique(_config.filename, _config.evmVersion); } - SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion): - CommonSyntaxTest(_filename, _evmVersion) {} + SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion); virtual ~SyntaxTest() {} - - /// Validates the settings, i.e. moves them from m_settings to m_validatedSettings. - /// Throws a runtime exception if any setting is left at this class (i.e. unknown setting). - void validateSettings() override; protected: void parseAndAnalyze() override; + +private: + std::string m_dialectName; }; } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index f37d18383b22..937ffb57e7d3 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -45,17 +45,11 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -YulInterpreterTest::YulInterpreterTest(string const& _filename) +YulInterpreterTest::YulInterpreterTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { - boost::filesystem::path path(_filename); - - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_source = parseSourceAndSettings(file); - m_expectation = parseSimpleExpectations(file); + m_source = m_reader.source(); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult YulInterpreterTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index e488460fccda..c8cb601f1e95 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -89,7 +89,8 @@ using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace std; -YulOptimizerTest::YulOptimizerTest(string const& _filename) +YulOptimizerTest::YulOptimizerTest(string const& _filename): + EVMVersionRestrictedTestCase(_filename) { boost::filesystem::path path(_filename); @@ -97,38 +98,23 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\".")); m_optimizerStep = std::prev(std::prev(path.end()))->string(); - ifstream file(_filename); - soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); - file.exceptions(ios::badbit); + m_source = m_reader.source(); - m_source = parseSourceAndSettings(file); - if (m_settings.count("dialect")) - { - auto dialectName = m_settings["dialect"]; - if (dialectName == "yul") - m_dialect = &Dialect::yulDeprecated(); - else if (dialectName == "ewasm") - m_dialect = &WasmDialect::instance(); - else if (dialectName == "evm") - m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()); - else if (dialectName == "evmTyped") - m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion()); - else - BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName)); - - m_validatedSettings["dialect"] = dialectName; - m_settings.erase("dialect"); - } - else + auto dialectName = m_reader.stringSetting("dialect", "evm"); + if (dialectName == "yul") + m_dialect = &Dialect::yulDeprecated(); + else if (dialectName == "ewasm") + m_dialect = &WasmDialect::instance(); + else if (dialectName == "evm") m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()); + else if (dialectName == "evmTyped") + m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion()); + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName)); - if (m_settings.count("step")) - { - m_validatedSettings["step"] = m_settings["step"]; - m_settings.erase("step"); - } + m_step = m_reader.stringSetting("step", ""); - m_expectation = parseSimpleExpectations(file); + m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) @@ -377,13 +363,13 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n"; - if (m_optimizerStep != m_validatedSettings["step"]) + if (m_optimizerStep != m_step) { string nextIndentLevel = _linePrefix + " "; AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Invalid optimizer step. Given: \"" << - m_validatedSettings["step"] << + m_step << "\", should be: \"" << m_optimizerStep << "\"." << @@ -410,7 +396,8 @@ void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix, void YulOptimizerTest::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool _formatted) { - m_validatedSettings["step"] = m_optimizerStep; + m_step = m_optimizerStep; + m_reader.setSetting("step", m_step); EVMVersionRestrictedTestCase::printUpdatedSettings(_stream, _linePrefix, _formatted); } diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 41e38fca050b..64e3cc83dfd7 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -73,6 +73,7 @@ class YulOptimizerTest: public solidity::frontend::test::EVMVersionRestrictedTes std::string m_expectation; Dialect const* m_dialect = nullptr; + std::string m_step; std::set m_reservedIdentifiers; std::unique_ptr m_nameDispenser; std::unique_ptr m_context; diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 5ea8486ec5f5..c8add4ce7ab1 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(isoltest ../CommonSyntaxTest.cpp ../EVMHost.cpp ../TestCase.cpp + ../TestCaseReader.cpp ../libsolidity/util/BytesUtils.cpp ../libsolidity/util/ContractABIUtils.cpp ../libsolidity/util/TestFileParser.cpp diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index e439aba64dd7..da85c9ed0012 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -161,7 +161,6 @@ TestTool::Result TestTool::process() (AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush(); m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()}); - m_test->validateSettings(); if (m_test->shouldRun()) switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted)) { From bb38ce17598bd369fbe43aac7396661d415041c8 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sat, 7 Mar 2020 01:18:42 +0100 Subject: [PATCH 056/165] Decoupled error checking and report printing in CommonSyntaxTest. --- test/CommonSyntaxTest.cpp | 28 ++++++++++++++----------- test/CommonSyntaxTest.h | 3 ++- test/libsolidity/SMTCheckerJSONTest.cpp | 2 +- test/libsolidity/SMTCheckerTest.cpp | 2 +- test/libsolidity/SyntaxTest.cpp | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index ebc80dc2f128..e3edc3fb0e0d 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -68,21 +68,25 @@ TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _line { parseAndAnalyze(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } -bool CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +TestCase::TestResult CommonSyntaxTest::conclude(ostream& _stream, string const& _linePrefix, bool _formatted) { - if (m_expectations != m_errorList) - { - string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; - printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; - printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); - return false; - } - return true; + if (m_expectations == m_errorList) + return TestResult::Success; + + printExpectationAndError(_stream, _linePrefix, _formatted); + return TestResult::Failure; +} + +void CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + string nextIndentLevel = _linePrefix + " "; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); } void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const diff --git a/test/CommonSyntaxTest.h b/test/CommonSyntaxTest.h index 22acd5413a14..e761e1487e82 100644 --- a/test/CommonSyntaxTest.h +++ b/test/CommonSyntaxTest.h @@ -73,7 +73,8 @@ class CommonSyntaxTest: public frontend::test::EVMVersionRestrictedTestCase bool _formatted = false ); - virtual bool printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); + TestResult conclude(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); + void printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); static std::vector parseExpectations(std::istream& _stream); diff --git a/test/libsolidity/SMTCheckerJSONTest.cpp b/test/libsolidity/SMTCheckerJSONTest.cpp index fad5a127f7aa..a1c23662ad0c 100644 --- a/test/libsolidity/SMTCheckerJSONTest.cpp +++ b/test/libsolidity/SMTCheckerJSONTest.cpp @@ -135,7 +135,7 @@ TestCase::TestResult SMTCheckerJSONTest::run(ostream& _stream, string const& _li } } - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } vector SMTCheckerJSONTest::hashesFromJson(Json::Value const& _jsonObj, string const& _auxInput, string const& _smtlib) diff --git a/test/libsolidity/SMTCheckerTest.cpp b/test/libsolidity/SMTCheckerTest.cpp index f0bfed8d4b61..28c98ffab3a6 100644 --- a/test/libsolidity/SMTCheckerTest.cpp +++ b/test/libsolidity/SMTCheckerTest.cpp @@ -57,5 +57,5 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr parseAndAnalyze(); filterObtainedErrors(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 031a6085f939..3ec506998490 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -47,7 +47,7 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix parseAndAnalyze(); filterObtainedErrors(); - return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; + return conclude(_stream, _linePrefix, _formatted); } void SyntaxTest::setupCompiler() From a5ae51fa6e1a9f19598ecf86564c10cc4f621661 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Mon, 9 Mar 2020 00:40:54 +0100 Subject: [PATCH 057/165] Unified dialect selection in libyul/SyntaxTest and YulOptimizerTest. --- test/libyul/Common.cpp | 49 ++++++++++++++++++++++++++ test/libyul/Common.h | 4 +++ test/libyul/SyntaxTest.cpp | 59 ++++---------------------------- test/libyul/SyntaxTest.h | 2 +- test/libyul/YulOptimizerTest.cpp | 11 +----- 5 files changed, 62 insertions(+), 63 deletions(-) diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index ff1517eecd5f..ee6d77dab750 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -106,3 +107,51 @@ string yul::test::format(string const& _source, bool _yul) { return yul::AsmPrinter()(*parse(_source, _yul).first); } + +namespace +{ +std::map const validDialects = { + { + "evm", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialect::strictAssemblyForEVMObjects(_evmVersion); } + }, + { + "evmTyped", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialectTyped::instance(_evmVersion); } + }, + { + "yul", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::Dialect::yulDeprecated(); } + }, + { + "ewasm", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::WasmDialect::instance(); } + } +}; + +vector validDialectNames() +{ + vector names{size(validDialects), ""}; + transform(begin(validDialects), end(validDialects), names.begin(), [](auto const& dialect) { return dialect.first; }); + + return names; +} +} + +yul::Dialect const& yul::test::dialect(std::string const& _name, langutil::EVMVersion _evmVersion) +{ + if (!validDialects.count(_name)) + BOOST_THROW_EXCEPTION(runtime_error{ + "Invalid Dialect \"" + + _name + + "\". Valid dialects are " + + util::joinHumanReadable(validDialectNames(), ", ", " and ") + + "." + }); + + return validDialects.at(_name)(_evmVersion); +} diff --git a/test/libyul/Common.h b/test/libyul/Common.h index 0b154e69cd61..b5f175ac283d 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -23,6 +23,8 @@ #include +#include + #include #include #include @@ -53,4 +55,6 @@ parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& Block disambiguate(std::string const& _source, bool _yul = true); std::string format(std::string const& _source, bool _yul = true); +solidity::yul::Dialect const& dialect(std::string const& _name, langutil::EVMVersion _evmVersion); + } diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index 8e5862b43f40..05accb695057 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -19,59 +19,22 @@ #include #include -#include -#include -#include - #include #include +#include #include +#include + using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::langutil; using namespace solidity::yul::test; -namespace -{ -std::map const validDialects = { - { - "evm", - [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& - { return yul::EVMDialect::strictAssemblyForEVM(_evmVersion); } - }, - { - "evmTyped", - [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& - { return yul::EVMDialectTyped::instance(_evmVersion); } - }, - { - "yul", - [](langutil::EVMVersion) -> yul::Dialect const& - { return yul::Dialect::yulDeprecated(); } - }, - { - "ewasm", - [](langutil::EVMVersion) -> yul::Dialect const& - { return yul::WasmDialect::instance(); } - } -}; - -vector validDialectNames() -{ - vector names{size(validDialects), ""}; - transform(begin(validDialects), end(validDialects), names.begin(), [](auto const& dialect) { return dialect.first; }); - - return names; -} -} - void SyntaxTest::parseAndAnalyze() { - yul::Dialect const& dialect = validDialects.at(m_dialectName)(m_evmVersion); - if (m_sources.size() != 1) BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."}); @@ -82,12 +45,12 @@ void SyntaxTest::parseAndAnalyze() ErrorReporter errorReporter{errorList}; auto scanner = make_shared(CharStream(source, name)); - auto parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false); + auto parserResult = yul::Parser(errorReporter, *m_dialect).parse(scanner, false); if (parserResult) { yul::AsmAnalysisInfo analysisInfo; - yul::AsmAnalyzer(analysisInfo, errorReporter, dialect).analyze(*parserResult); + yul::AsmAnalyzer(analysisInfo, errorReporter, *m_dialect).analyze(*parserResult); } for (auto const& error: errorList) @@ -115,14 +78,6 @@ void SyntaxTest::parseAndAnalyze() SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): CommonSyntaxTest(_filename, _evmVersion) { - m_dialectName = m_reader.stringSetting("dialect", "evmTyped"); - - if (!validDialects.count(m_dialectName)) - BOOST_THROW_EXCEPTION(runtime_error{ - "Invalid Dialect \"" + - m_dialectName + - "\". Valid dialects are " + - joinHumanReadable(validDialectNames(), ", ", " and ") + - "." - }); + string dialectName = m_reader.stringSetting("dialect", "evmTyped"); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); } diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h index 8b4c24bd83fa..b4c838b54a47 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -42,7 +42,7 @@ class SyntaxTest: public solidity::test::CommonSyntaxTest void parseAndAnalyze() override; private: - std::string m_dialectName; + Dialect const* m_dialect = nullptr; }; } diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index c8cb601f1e95..6ab4b181fa9b 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -101,16 +101,7 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename): m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); - if (dialectName == "yul") - m_dialect = &Dialect::yulDeprecated(); - else if (dialectName == "ewasm") - m_dialect = &WasmDialect::instance(); - else if (dialectName == "evm") - m_dialect = &EVMDialect::strictAssemblyForEVMObjects(solidity::test::CommonOptions::get().evmVersion()); - else if (dialectName == "evmTyped") - m_dialect = &EVMDialectTyped::instance(solidity::test::CommonOptions::get().evmVersion()); - else - BOOST_THROW_EXCEPTION(runtime_error("Invalid dialect " + dialectName)); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); m_step = m_reader.stringSetting("step", ""); From e2db9d7ef39283e1306b2958f70e5683cd138a44 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 9 Mar 2020 13:25:26 +0100 Subject: [PATCH 058/165] Disallow private functions from being overridden --- Changelog.md | 5 +++++ docs/bugs_by_version.json | 4 ++++ libsolidity/analysis/ContractLevelChecker.cpp | 3 +++ test/externalTests/zeppelin.sh | 2 +- .../inheritance/override/override_private.sol | 8 ++++++++ .../inheritance/override/override_private1.sol | 8 ++++++++ .../inheritance/override/override_private2.sol | 9 +++++++++ .../inheritance/override/override_private_multi.sol | 11 +++++++++++ .../inheritance/override/override_private_multi1.sol | 11 +++++++++++ .../inheritance/override/override_private_multi2.sol | 12 ++++++++++++ test/solcjsTests.sh | 1 + 11 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private1.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private2.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private_multi.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private_multi1.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/override_private_multi2.sol diff --git a/Changelog.md b/Changelog.md index 72461f021077..e7a43645cb42 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,8 @@ +### 0.5.17 (2020-03-17) + +Bugfixes: + * Type Checker: Disallow overriding of private functions. + ### 0.5.16 (2020-01-02) Bugfixes: diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index a9ce0be92f7a..00bca1f3bb10 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -782,6 +782,10 @@ "bugs": [], "released": "2020-01-02" }, + "0.5.17": { + "bugs": [], + "released": "2020-03-17" + }, "0.5.2": { "bugs": [ "SignedArrayStorageCopy", diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 95626bb2ab4f..57ca62fecce6 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -203,6 +203,9 @@ void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _func stateMutabilityToString(_function.stateMutability()) + "\"." ); + if (_super.visibility() == Declaration::Visibility::Private) + overrideError(_function, _super, "Private functions cannot be overridden."); + } void ContractLevelChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message) diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index aa784c6adff4..2eb467acdaf7 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -31,7 +31,7 @@ function test_fn { npm run test; } function zeppelin_test { OPTIMIZER_LEVEL=1 - setup https://github.com/OpenZeppelin/openzeppelin-solidity.git master + setup https://github.com/OpenZeppelin/openzeppelin-solidity.git v2.5.0 run_install install_fn CONFIG="truffle-config.js" diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private.sol new file mode 100644 index 000000000000..f5e33db4cf38 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private.sol @@ -0,0 +1,8 @@ +contract A { + function test() private returns (uint256) {} +} +contract X is A { + function test() private returns (uint256) {} +} +// ---- +// TypeError: (80-124): Private functions cannot be overridden. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private1.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private1.sol new file mode 100644 index 000000000000..127aee5567c0 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private1.sol @@ -0,0 +1,8 @@ +contract A { + function test() public returns (uint256) {} +} +contract X is A { + function test() private returns (uint256) {} +} +// ---- +// TypeError: (79-123): Overriding function visibility differs. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private2.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private2.sol new file mode 100644 index 000000000000..98d687f51a2f --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private2.sol @@ -0,0 +1,9 @@ +contract A { + function test() private returns (uint256) {} +} +contract X is A { + function test() public returns (uint256) {} +} +// ---- +// TypeError: (80-123): Overriding function visibility differs. +// TypeError: (80-123): Private functions cannot be overridden. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private_multi.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi.sol new file mode 100644 index 000000000000..1a159477a20d --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi.sol @@ -0,0 +1,11 @@ +contract A { + function test() private returns (uint256) {} +} +contract B { + function test() private returns (uint256) {} +} + +contract X is A, B { +} +// ---- +// TypeError: (75-119): Private functions cannot be overridden. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private_multi1.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi1.sol new file mode 100644 index 000000000000..efedd5b92dce --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi1.sol @@ -0,0 +1,11 @@ +contract A { + function test() public returns (uint256) {} +} +contract B { + function test() private returns (uint256) {} +} + +contract X is A, B { +} +// ---- +// TypeError: (74-118): Overriding function visibility differs. diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_private_multi2.sol b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi2.sol new file mode 100644 index 000000000000..5825b8a79173 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/override_private_multi2.sol @@ -0,0 +1,12 @@ +contract A { + function test() private returns (uint256) {} +} +contract B { + function test() public returns (uint256) {} +} + +contract X is A, B { +} +// ---- +// TypeError: (75-118): Overriding function visibility differs. +// TypeError: (75-118): Private functions cannot be overridden. diff --git a/test/solcjsTests.sh b/test/solcjsTests.sh index d525a3f21442..5c918de29435 100755 --- a/test/solcjsTests.sh +++ b/test/solcjsTests.sh @@ -58,6 +58,7 @@ DIR=$(mktemp -d) npm version --allow-same-version --no-git-tag-version $VERSION echo "Running solc-js tests..." + sed -i -e 's/latest/v0.5.0+commit.1d4f565a/' test/package.js npm run test ) rm -rf "$DIR" From d19bba13196b8c9091e5d81581015baafca94dd8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 17 Mar 2020 17:45:53 +0100 Subject: [PATCH 059/165] Set version to 0.5.17. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c84c6d15d34..f0c1dd42969e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.5.16") +set(PROJECT_VERSION "0.5.17") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) include(TestBigEndian) From 63f13c5b18c6828b0f190491fb3643eb7fedfbe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 1 Mar 2020 14:34:23 +0100 Subject: [PATCH 060/165] [yul-phaser] Add --chromosome-repetitions option --- tools/yulPhaser/Phaser.cpp | 22 ++++++++++++++++++++-- tools/yulPhaser/Phaser.h | 8 +++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 5f0e3d87b1be..f02e942f77be 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -96,11 +96,19 @@ unique_ptr GeneticAlgorithmFactory::build( } } +FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["chromosome-repetitions"].as(), + }; +} + unique_ptr FitnessMetricFactory::build( + Options const& _options, Program _program ) { - return make_unique(move(_program), RepetitionCount); + return make_unique(move(_program), _options.chromosomeRepetitions); } Population PopulationFactory::build( @@ -190,6 +198,15 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ; keywordDescription.add(algorithmDescription); + po::options_description metricsDescription("METRICS", lineLength, minDescriptionLength); + metricsDescription.add_options() + ( + "chromosome-repetitions", + po::value()->value_name("")->default_value(1), + "Number of times to repeat the sequence optimisation steps represented by a chromosome." + ) + ; + keywordDescription.add(metricsDescription); po::positional_options_description positionalDescription; positionalDescription.add("input-file", 1); @@ -235,10 +252,11 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments) void Phaser::runAlgorithm(po::variables_map const& _arguments) { auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); + auto metricOptions = FitnessMetricFactory::Options::fromCommandLine(_arguments); auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); Program program = ProgramFactory::build(programOptions); - unique_ptr fitnessMetric = FitnessMetricFactory::build(move(program)); + unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(program)); Population population = PopulationFactory::build(move(fitnessMetric)); unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 9ac6f81f02c8..20d9ace25fac 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -80,9 +80,15 @@ class GeneticAlgorithmFactory class FitnessMetricFactory { public: - static constexpr size_t RepetitionCount = 5; + struct Options + { + size_t chromosomeRepetitions; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; static std::unique_ptr build( + Options const& _options, Program _program ); }; From d8e5f8f9653e6b6ee196136a9f978f15e49d9329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 21 Feb 2020 20:01:00 +0100 Subject: [PATCH 061/165] [yul-phaser] Add --rounds option --- tools/yulPhaser/Phaser.cpp | 14 +++++++++++++- tools/yulPhaser/Phaser.h | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index f02e942f77be..3d45db1e8317 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -185,6 +185,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ("help", "Show help message and exit.") ("input-file", po::value()->required()->value_name(""), "Input file.") ("seed", po::value()->value_name(""), "Seed for the random number generator.") + ( + "rounds", + po::value()->value_name(""), + "The number of rounds after which the algorithm should stop. (default=no limit)." + ) ; keywordDescription.add(generalDescription); @@ -249,6 +254,13 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments) cout << "Random seed: " << seed << endl; } +AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map const& _arguments) +{ + return { + _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt + }; +} + void Phaser::runAlgorithm(po::variables_map const& _arguments) { auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); @@ -266,6 +278,6 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) PopulationFactory::MaxChromosomeLength ); - AlgorithmRunner algorithmRunner(population, AlgorithmRunner::Options{}, cout); + AlgorithmRunner algorithmRunner(population, buildAlgorithmRunnerOptions(_arguments), cout); algorithmRunner.run(*geneticAlgorithm); } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 20d9ace25fac..ac6f70defa76 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include @@ -147,6 +149,7 @@ class Phaser static CommandLineDescription buildCommandLineDescription(); static std::optional parseCommandLine(int _argc, char** _argv); static void initialiseRNG(boost::program_options::variables_map const& _arguments); + static AlgorithmRunner::Options buildAlgorithmRunnerOptions(boost::program_options::variables_map const& _arguments); static void runAlgorithm(boost::program_options::variables_map const& _arguments); }; From af090876b508f6d2f55641a6e0ab1dc2546edf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 00:00:29 +0100 Subject: [PATCH 062/165] [yul-phaser] Add --random-population option --- tools/yulPhaser/Phaser.cpp | 45 ++++++++++++++++++++++++++++++++++++-- tools/yulPhaser/Phaser.h | 13 ++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 3d45db1e8317..768088e4957c 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -111,13 +111,43 @@ unique_ptr FitnessMetricFactory::build( return make_unique(move(_program), _options.chromosomeRepetitions); } +PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments.count("random-population") > 0 ? + _arguments["random-population"].as>() : + vector{}, + }; +} + Population PopulationFactory::build( + Options const& _options, + shared_ptr _fitnessMetric +) +{ + Population population(_fitnessMetric, vector{}); + + size_t combinedSize = 0; + for (size_t populationSize: _options.randomPopulation) + combinedSize += populationSize; + + population = move(population) + buildRandom( + combinedSize, + _fitnessMetric + ); + + return population; +} + + +Population PopulationFactory::buildRandom( + size_t _populationSize, shared_ptr _fitnessMetric ) { return Population::makeRandom( move(_fitnessMetric), - PopulationSize, + _populationSize, MinChromosomeLength, MaxChromosomeLength ); @@ -203,6 +233,16 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ; keywordDescription.add(algorithmDescription); + po::options_description populationDescription("POPULATION", lineLength, minDescriptionLength); + populationDescription.add_options() + ( + "random-population", + po::value>()->value_name(""), + "The number of randomly generated chromosomes to be included in the initial population." + ) + ; + keywordDescription.add(populationDescription); + po::options_description metricsDescription("METRICS", lineLength, minDescriptionLength); metricsDescription.add_options() ( @@ -265,11 +305,12 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) { auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); auto metricOptions = FitnessMetricFactory::Options::fromCommandLine(_arguments); + auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments); auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); Program program = ProgramFactory::build(programOptions); unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(program)); - Population population = PopulationFactory::build(move(fitnessMetric)); + Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( algorithmOptions, diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index ac6f70defa76..4df0109f7f2f 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -101,11 +101,22 @@ class FitnessMetricFactory class PopulationFactory { public: - static constexpr size_t PopulationSize = 20; static constexpr size_t MinChromosomeLength = 12; static constexpr size_t MaxChromosomeLength = 30; + struct Options + { + std::vector randomPopulation; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + static Population build( + Options const& _options, + std::shared_ptr _fitnessMetric + ); + static Population buildRandom( + size_t _populationSize, std::shared_ptr _fitnessMetric ); }; From 5e00b57e02a435cb752502d11bc50b306aa97f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 00:01:06 +0100 Subject: [PATCH 063/165] [yul-phaser] Add --population option --- tools/yulPhaser/Phaser.cpp | 23 ++++++++++++++++++++++- tools/yulPhaser/Phaser.h | 5 +++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 768088e4957c..8c5fcbc26389 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -114,6 +114,9 @@ unique_ptr FitnessMetricFactory::build( PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { + _arguments.count("population") > 0 ? + _arguments["population"].as>() : + vector{}, _arguments.count("random-population") > 0 ? _arguments["random-population"].as>() : vector{}, @@ -125,7 +128,7 @@ Population PopulationFactory::build( shared_ptr _fitnessMetric ) { - Population population(_fitnessMetric, vector{}); + Population population = buildFromStrings(_options.population, _fitnessMetric); size_t combinedSize = 0; for (size_t populationSize: _options.randomPopulation) @@ -139,6 +142,17 @@ Population PopulationFactory::build( return population; } +Population PopulationFactory::buildFromStrings( + vector const& _geneSequences, + shared_ptr _fitnessMetric +) +{ + vector chromosomes; + for (string const& geneSequence: _geneSequences) + chromosomes.emplace_back(geneSequence); + + return Population(move(_fitnessMetric), move(chromosomes)); +} Population PopulationFactory::buildRandom( size_t _populationSize, @@ -235,6 +249,13 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::options_description populationDescription("POPULATION", lineLength, minDescriptionLength); populationDescription.add_options() + ( + "population", + po::value>()->multitoken()->value_name(""), + "List of chromosomes to be included in the initial population. " + "You can specify multiple values separated with spaces or invoke the option multiple times " + "and all the values will be included." + ) ( "random-population", po::value>()->value_name(""), diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 4df0109f7f2f..a12ccd87ac0a 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -106,6 +106,7 @@ class PopulationFactory struct Options { + std::vector population; std::vector randomPopulation; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); @@ -115,6 +116,10 @@ class PopulationFactory Options const& _options, std::shared_ptr _fitnessMetric ); + static Population buildFromStrings( + std::vector const& _geneSequences, + std::shared_ptr _fitnessMetric + ); static Population buildRandom( size_t _populationSize, std::shared_ptr _fitnessMetric From 5e814acc3c632429d4523b4bf4a5c7d0a96367ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 4 Mar 2020 14:25:31 +0100 Subject: [PATCH 064/165] [yul-phaser] TestHelpers: Add TemporaryDirectory class --- test/yulPhaser/TestHelpers.cpp | 40 ++++++++++++++++++++ test/yulPhaser/TestHelpers.h | 25 ++++++++++++ test/yulPhaser/TestHelpersTest.cpp | 61 ++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) diff --git a/test/yulPhaser/TestHelpers.cpp b/test/yulPhaser/TestHelpers.cpp index b52cee084e89..2379016fe246 100644 --- a/test/yulPhaser/TestHelpers.cpp +++ b/test/yulPhaser/TestHelpers.cpp @@ -19,12 +19,18 @@ #include +#include + #include +#include using namespace std; using namespace solidity; using namespace solidity::yul; using namespace solidity::phaser; +using namespace solidity::phaser::test; + +namespace fs = boost::filesystem; function phaser::test::wholeChromosomeReplacement(Chromosome _newChromosome) { @@ -71,6 +77,40 @@ size_t phaser::test::countDifferences(Chromosome const& _chromosome1, Chromosome return count + abs(static_cast(_chromosome1.length() - _chromosome2.length())); } +TemporaryDirectory::TemporaryDirectory(std::string const& _prefix): + m_path((fs::temp_directory_path() / fs::unique_path(_prefix + "%%%%-%%%%-%%%%-%%%%")).string()) +{ + // Prefix should just be a file name and not contain anything that would make us step out of /tmp. + assert(fs::path(_prefix) == fs::path(_prefix).stem()); + + fs::create_directory(m_path); +} + +TemporaryDirectory::~TemporaryDirectory() +{ + // A few paranoid sanity checks just to be extra sure we're not deleting someone's homework. + assert(m_path.find(fs::temp_directory_path().string()) == 0); + assert(fs::path(m_path) != fs::temp_directory_path()); + assert(fs::path(m_path) != fs::path(m_path).root_path()); + assert(!fs::path(m_path).empty()); + + boost::system::error_code errorCode; + uintmax_t numRemoved = fs::remove_all(m_path, errorCode); + if (errorCode.value() != boost::system::errc::success) + { + cerr << "Failed to completely remove temporary directory '" << m_path << "'. "; + cerr << "Only " << numRemoved << " files were actually removed." << endl; + cerr << "Reason: " << errorCode.message() << endl; + } +} + +string TemporaryDirectory::memberPath(string const& _relativePath) const +{ + assert(fs::path(_relativePath).is_relative()); + + return (fs::path(m_path) / _relativePath).string(); +} + string phaser::test::stripWhitespace(string const& input) { regex whitespaceRegex("\\s+"); diff --git a/test/yulPhaser/TestHelpers.h b/test/yulPhaser/TestHelpers.h index a59c7eed123c..aa76ae6da18a 100644 --- a/test/yulPhaser/TestHelpers.h +++ b/test/yulPhaser/TestHelpers.h @@ -79,6 +79,31 @@ size_t countDifferences(Chromosome const& _chromosome1, Chromosome const& _chrom /// integers. std::map enumerateOptmisationSteps(); +// FILESYSTEM UTILITIES + +/** + * An object that creates a unique temporary directory and automatically deletes it and its + * content upon being destroyed. + * + * The directory is guaranteed to be newly created and empty. Directory names are generated + * randomly. If a directory with the same name already exists (very unlikely but possible) the + * object won't reuse it and will fail with an exception instead. + */ +class TemporaryDirectory +{ +public: + TemporaryDirectory(std::string const& _prefix = "yul-phaser-test-"); + ~TemporaryDirectory(); + + std::string const& path() const { return m_path; } + + /// Converts a path relative to the directory held by the object into an absolute one. + std::string memberPath(std::string const& _relativePath) const; + +private: + std::string m_path; +}; + // STRING UTILITIES /// Returns the input string with all the whitespace characters (spaces, line endings, etc.) removed. diff --git a/test/yulPhaser/TestHelpersTest.cpp b/test/yulPhaser/TestHelpersTest.cpp index 98d609050693..7fc4ef0afa90 100644 --- a/test/yulPhaser/TestHelpersTest.cpp +++ b/test/yulPhaser/TestHelpersTest.cpp @@ -19,14 +19,18 @@ #include +#include #include +#include #include using namespace std; using namespace solidity::yul; using namespace boost::test_tools; +namespace fs = boost::filesystem; + namespace solidity::phaser::test { @@ -114,6 +118,63 @@ BOOST_AUTO_TEST_CASE(enumerateOptimisationSteps_should_assing_indices_to_all_ava } } +BOOST_AUTO_TEST_CASE(TemporaryDirectory_should_create_and_delete_a_unique_and_empty_directory) +{ + fs::path dirPath; + { + TemporaryDirectory tempDir("temporary-directory-test-"); + dirPath = tempDir.path(); + + BOOST_TEST(dirPath.stem().string().find("temporary-directory-test-") == 0); + BOOST_TEST(fs::equivalent(dirPath.parent_path(), fs::temp_directory_path())); + BOOST_TEST(fs::is_directory(dirPath)); + BOOST_TEST(fs::is_empty(dirPath)); + } + BOOST_TEST(!fs::exists(dirPath)); +} + +BOOST_AUTO_TEST_CASE(TemporaryDirectory_should_delete_its_directory_even_if_not_empty) +{ + fs::path dirPath; + { + TemporaryDirectory tempDir("temporary-directory-test-"); + dirPath = tempDir.path(); + + BOOST_TEST(fs::is_directory(dirPath)); + + { + ofstream tmpFile((dirPath / "test-file.txt").string()); + tmpFile << "Delete me!" << endl; + } + assert(fs::is_regular_file(dirPath / "test-file.txt")); + } + BOOST_TEST(!fs::exists(dirPath / "test-file.txt")); +} + +BOOST_AUTO_TEST_CASE(TemporaryDirectory_memberPath_should_construct_paths_relative_to_the_temporary_directory) +{ + TemporaryDirectory tempDir("temporary-directory-test-"); + + BOOST_TEST(fs::equivalent(tempDir.memberPath(""), tempDir.path())); + BOOST_TEST(fs::equivalent(tempDir.memberPath("."), tempDir.path() / fs::path("."))); + BOOST_TEST(fs::equivalent(tempDir.memberPath(".."), tempDir.path() / fs::path(".."))); + + // NOTE: fs::equivalent() only works with paths that actually exist + { + ofstream file; + file.open(tempDir.memberPath("file.txt"), ios::out); + } + BOOST_TEST(fs::equivalent(tempDir.memberPath("file.txt"), tempDir.path() / fs::path("file.txt"))); + + { + fs::create_directories(tempDir.memberPath("a/b/")); + + ofstream file; + file.open(tempDir.memberPath("a/b/file.txt"), ios::out); + } + BOOST_TEST(fs::equivalent(tempDir.memberPath("a/b/file.txt"), tempDir.path() / fs::path("a") / fs::path("b") / fs::path("file.txt"))); +} + BOOST_AUTO_TEST_CASE(stripWhitespace_should_remove_all_whitespace_characters_from_a_string) { BOOST_TEST(stripWhitespace("") == ""); From ff99d25bc36309d9931f2b7c938c199bba51fa60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 00:48:35 +0100 Subject: [PATCH 065/165] [yul-phaser] Common: Add readLinesFromFile() --- test/CMakeLists.txt | 1 + test/yulPhaser/Common.cpp | 20 ++++++++++++++++ tools/CMakeLists.txt | 1 + tools/yulPhaser/Common.cpp | 45 ++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Common.h | 9 ++++++++ tools/yulPhaser/Exceptions.h | 3 +++ 6 files changed, 79 insertions(+) create mode 100644 tools/yulPhaser/Common.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fa9127e7223f..d5bf4b686e98 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -158,6 +158,7 @@ set(yul_phaser_sources # My current workaround is just to include its source files here but this introduces # unnecessary duplication. Create a library or find a way to reuse the list in both places. ../tools/yulPhaser/AlgorithmRunner.cpp + ../tools/yulPhaser/Common.cpp ../tools/yulPhaser/Chromosome.cpp ../tools/yulPhaser/FitnessMetrics.cpp ../tools/yulPhaser/GeneticAlgorithms.cpp diff --git a/test/yulPhaser/Common.cpp b/test/yulPhaser/Common.cpp index 891495193049..39e6dd7843fe 100644 --- a/test/yulPhaser/Common.cpp +++ b/test/yulPhaser/Common.cpp @@ -15,6 +15,8 @@ along with solidity. If not, see . */ +#include + #include #include @@ -22,6 +24,7 @@ #include #include +#include #include #include @@ -32,6 +35,12 @@ using namespace solidity::util; namespace solidity::phaser::test { +class ReadLinesFromFileFixture +{ +protected: + TemporaryDirectory m_tempDir; +}; + namespace { @@ -60,6 +69,17 @@ map const StringToTestEnumMap = invertMap(TestEnumToStringMap) BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(CommonTest) +BOOST_FIXTURE_TEST_CASE(readLinesFromFile_should_return_all_lines_from_a_text_file_as_strings_without_newlines, ReadLinesFromFileFixture) +{ + { + ofstream tmpFile(m_tempDir.memberPath("test-file.txt")); + tmpFile << endl << "Line 1" << endl << endl << endl << "Line 2" << endl << "#" << endl << endl; + } + + vector lines = readLinesFromFile(m_tempDir.memberPath("test-file.txt")); + BOOST_TEST((lines == vector{"", "Line 1", "", "", "Line 2", "#", ""})); +} + BOOST_AUTO_TEST_CASE(deserializeChoice_should_convert_string_to_enum) { istringstream aStream("a"); diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index fb2d411b5bd6..fd5f92bbe1ef 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -16,6 +16,7 @@ install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}") add_executable(yul-phaser yulPhaser/main.cpp yulPhaser/Common.h + yulPhaser/Common.cpp yulPhaser/AlgorithmRunner.h yulPhaser/AlgorithmRunner.cpp yulPhaser/Phaser.h diff --git a/tools/yulPhaser/Common.cpp b/tools/yulPhaser/Common.cpp new file mode 100644 index 000000000000..aa7ba85b5c26 --- /dev/null +++ b/tools/yulPhaser/Common.cpp @@ -0,0 +1,45 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::phaser; + +vector phaser::readLinesFromFile(string const& _path) +{ + ifstream inputStream(_path); + assertThrow(inputStream.is_open(), FileOpenError, "Could not open file '" + _path + "': " + strerror(errno)); + + string line; + vector lines; + while (!getline(inputStream, line).fail()) + lines.push_back(line); + + assertThrow(!inputStream.bad(), FileReadError, "Error while reading from file '" + _path + "': " + strerror(errno)); + + return lines; +} diff --git a/tools/yulPhaser/Common.h b/tools/yulPhaser/Common.h index 9bf3f6204e81..c37afa2fbd22 100644 --- a/tools/yulPhaser/Common.h +++ b/tools/yulPhaser/Common.h @@ -22,10 +22,19 @@ #include #include +#include +#include namespace solidity::phaser { +/// Loads the whole file into memory, splits the content into lines, strips newlines and +/// returns the result as a list of strings. +/// +/// Throws FileOpenError if the file does not exist or cannot be opened for reading. +/// Throws FileReadError if any read operation fails during the whole process. +std::vector readLinesFromFile(std::string const& _path); + /// Reads a token from the input stream and translates it to a string using a map. /// Sets the failbit in the stream if there's no matching value in the map. template diff --git a/tools/yulPhaser/Exceptions.h b/tools/yulPhaser/Exceptions.h index 1f675a9ef5d2..e3a06fbed1b8 100644 --- a/tools/yulPhaser/Exceptions.h +++ b/tools/yulPhaser/Exceptions.h @@ -27,4 +27,7 @@ struct InvalidProgram: virtual BadInput {}; struct NoInputFiles: virtual BadInput {}; struct MissingFile: virtual BadInput {}; +struct FileOpenError: virtual util::Exception {}; +struct FileReadError: virtual util::Exception {}; + } From 04c7c56d84a24c0c6b056c17ef5f029e8b044958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 00:49:06 +0100 Subject: [PATCH 066/165] [yul-phaser] Add --population-from-file option --- tools/yulPhaser/Phaser.cpp | 19 +++++++++++++++++++ tools/yulPhaser/Phaser.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 8c5fcbc26389..c8bc38a96c8b 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -120,6 +120,9 @@ PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::varia _arguments.count("random-population") > 0 ? _arguments["random-population"].as>() : vector{}, + _arguments.count("population-from-file") > 0 ? + _arguments["population-from-file"].as>() : + vector{}, }; } @@ -139,6 +142,9 @@ Population PopulationFactory::build( _fitnessMetric ); + for (string const& populationFilePath: _options.populationFromFile) + population = move(population) + buildFromFile(populationFilePath, _fitnessMetric); + return population; } @@ -167,6 +173,14 @@ Population PopulationFactory::buildRandom( ); } +Population PopulationFactory::buildFromFile( + string const& _filePath, + shared_ptr _fitnessMetric +) +{ + return buildFromStrings(readLinesFromFile(_filePath), move(_fitnessMetric)); +} + ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { @@ -261,6 +275,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value>()->value_name(""), "The number of randomly generated chromosomes to be included in the initial population." ) + ( + "population-from-file", + po::value>()->value_name(""), + "A text file with a list of chromosomes (one per line) to be included in the initial population." + ) ; keywordDescription.add(populationDescription); diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index a12ccd87ac0a..63f570594374 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -108,6 +108,7 @@ class PopulationFactory { std::vector population; std::vector randomPopulation; + std::vector populationFromFile; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; @@ -124,6 +125,10 @@ class PopulationFactory size_t _populationSize, std::shared_ptr _fitnessMetric ); + static Population buildFromFile( + std::string const& _filePath, + std::shared_ptr _fitnessMetric + ); }; /** From 1b5960111d90a650dad554fb89ad02a762dc5e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 01:39:33 +0100 Subject: [PATCH 067/165] [yul-phaser] AlgorithmRunner: Population autosave --- test/yulPhaser/AlgorithmRunner.cpp | 101 +++++++++++++++++++++++++++- tools/yulPhaser/AlgorithmRunner.cpp | 34 ++++++++++ tools/yulPhaser/AlgorithmRunner.h | 3 + tools/yulPhaser/Exceptions.h | 1 + 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index f6102a9cb670..7b20d8db432b 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -18,9 +18,11 @@ #include #include +#include #include +#include #include #include @@ -29,10 +31,12 @@ using namespace boost::unit_test::framework; using namespace boost::test_tools; using namespace solidity::util; +namespace fs = boost::filesystem; + namespace solidity::phaser::test { -class DummyAlgorithm: public GeneticAlgorithm +class CountingAlgorithm: public GeneticAlgorithm { public: using GeneticAlgorithm::GeneticAlgorithm; @@ -45,6 +49,16 @@ class DummyAlgorithm: public GeneticAlgorithm size_t m_currentRound = 0; }; +class RandomisingAlgorithm: public GeneticAlgorithm +{ +public: + using GeneticAlgorithm::GeneticAlgorithm; + Population runNextRound(Population _population) override + { + return Population::makeRandom(_population.fitnessMetric(), _population.individuals().size(), 10, 20); + } +}; + class AlgorithmRunnerFixture { protected: @@ -53,6 +67,25 @@ class AlgorithmRunnerFixture AlgorithmRunner::Options m_options; }; +class AlgorithmRunnerAutosaveFixture: public AlgorithmRunnerFixture +{ +public: + static vector chromosomeStrings(Population const& _population) + { + vector lines; + for (auto const& individual: _population.individuals()) + lines.push_back(toString(individual.chromosome)); + + return lines; + } + +protected: + TemporaryDirectory m_tempDir; + string const m_autosavePath = m_tempDir.memberPath("population-autosave.txt"); + Population const m_population = Population::makeRandom(m_fitnessMetric, 5, 0, 20); + RandomisingAlgorithm m_algorithm; +}; + BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) @@ -60,7 +93,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRu { m_options.maxRounds = 5; AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output); - DummyAlgorithm algorithm; + + CountingAlgorithm algorithm; BOOST_TEST(algorithm.m_currentRound == 0); runner.run(algorithm); @@ -82,7 +116,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixt m_output ); - DummyAlgorithm algorithm; + CountingAlgorithm algorithm; BOOST_TEST(m_output.is_empty()); runner.run(algorithm); @@ -93,6 +127,67 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixt BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4); } +BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 0; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + assert(runner.population() == m_population); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population())); +} + +BOOST_FIXTURE_TEST_CASE(run_should_save_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 1; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + assert(runner.population() != m_population); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) == chromosomeStrings(runner.population())); +} + +BOOST_FIXTURE_TEST_CASE(run_should_overwrite_existing_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 5; + m_options.populationAutosaveFile = m_autosavePath; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + vector originalContent = {"Original content"}; + { + ofstream tmpFile(m_autosavePath); + tmpFile << originalContent[0] << endl; + } + assert(fs::exists(m_autosavePath)); + assert(readLinesFromFile(m_autosavePath) == originalContent); + + runner.run(m_algorithm); + + BOOST_TEST(fs::is_regular_file(m_autosavePath)); + BOOST_TEST(readLinesFromFile(m_autosavePath) != originalContent); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_not_specified, AlgorithmRunnerAutosaveFixture) +{ + m_options.maxRounds = 5; + m_options.populationAutosaveFile = nullopt; + AlgorithmRunner runner(m_population, m_options, m_output); + assert(!fs::exists(m_autosavePath)); + + runner.run(m_algorithm); + + BOOST_TEST(!fs::exists(m_autosavePath)); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 0efe19b7c7b1..a075fa785ac2 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -17,16 +17,50 @@ #include +#include + +#include + +#include +#include +#include + using namespace std; using namespace solidity::phaser; void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) { + populationAutosave(); + for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { m_population = _algorithm.runNextRound(m_population); m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; m_outputStream << m_population; + + populationAutosave(); } } + +void AlgorithmRunner::populationAutosave() const +{ + if (!m_options.populationAutosaveFile.has_value()) + return; + + ofstream outputStream(m_options.populationAutosaveFile.value(), ios::out | ios::trunc); + assertThrow( + outputStream.is_open(), + FileOpenError, + "Could not open file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) + ); + + for (auto& individual: m_population.individuals()) + outputStream << individual.chromosome << endl; + + assertThrow( + !outputStream.bad(), + FileWriteError, + "Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) + ); +} diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index c0aaa562134b..93c8348d580c 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -42,6 +42,7 @@ class AlgorithmRunner struct Options { std::optional maxRounds = std::nullopt; + std::optional populationAutosaveFile = std::nullopt; }; AlgorithmRunner( @@ -59,6 +60,8 @@ class AlgorithmRunner Population const& population() const { return m_population; } private: + void populationAutosave() const; + Population m_population; Options m_options; std::ostream& m_outputStream; diff --git a/tools/yulPhaser/Exceptions.h b/tools/yulPhaser/Exceptions.h index e3a06fbed1b8..6807d7180c1c 100644 --- a/tools/yulPhaser/Exceptions.h +++ b/tools/yulPhaser/Exceptions.h @@ -29,5 +29,6 @@ struct MissingFile: virtual BadInput {}; struct FileOpenError: virtual util::Exception {}; struct FileReadError: virtual util::Exception {}; +struct FileWriteError: virtual util::Exception {}; } From 3f7ada1689d1027eb1208c7647a309551e1aac20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 22 Feb 2020 01:39:56 +0100 Subject: [PATCH 068/165] [yul-phaser] Add --population-autosave option --- tools/yulPhaser/Phaser.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index c8bc38a96c8b..ee732298d318 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -280,6 +280,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value>()->value_name(""), "A text file with a list of chromosomes (one per line) to be included in the initial population." ) + ( + "population-autosave", + po::value()->value_name(""), + "If specified, the population is saved in the specified file after each round. (default=autosave disabled)" + ) ; keywordDescription.add(populationDescription); @@ -337,7 +342,8 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments) AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map const& _arguments) { return { - _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt + _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt, + _arguments.count("population-autosave") > 0 ? static_cast>(_arguments["population-autosave"].as()) : nullopt, }; } From 55ea92dbec7af62c71b9515909daad09b06a0e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 22:35:54 +0100 Subject: [PATCH 069/165] [yul-phaser] Add --min-chromosome-length and --max-chromosome-length options --- tools/yulPhaser/Phaser.cpp | 38 ++++++++++++++++++++++++++------------ tools/yulPhaser/Phaser.h | 13 +++++++------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index ee732298d318..97e4299681bf 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -62,14 +62,14 @@ GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLi { return { _arguments["algorithm"].as(), + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), }; } unique_ptr GeneticAlgorithmFactory::build( Options const& _options, - size_t _populationSize, - size_t _minChromosomeLength, - size_t _maxChromosomeLength + size_t _populationSize ) { assert(_populationSize > 0); @@ -79,8 +79,8 @@ unique_ptr GeneticAlgorithmFactory::build( case Algorithm::Random: return make_unique(RandomAlgorithm::Options{ /* elitePoolSize = */ 1.0 / _populationSize, - /* minChromosomeLength = */ _minChromosomeLength, - /* maxChromosomeLength = */ _maxChromosomeLength, + /* minChromosomeLength = */ _options.minChromosomeLength, + /* maxChromosomeLength = */ _options.maxChromosomeLength, }); case Algorithm::GEWEP: return make_unique(GenerationalElitistWithExclusivePools::Options{ @@ -88,8 +88,8 @@ unique_ptr GeneticAlgorithmFactory::build( /* crossoverPoolSize = */ 0.25, /* randomisationChance = */ 0.9, /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 1.0 / _maxChromosomeLength, - /* percentGenesToAddOrDelete = */ 1.0 / _maxChromosomeLength, + /* percentGenesToRandomise = */ 1.0 / _options.maxChromosomeLength, + /* percentGenesToAddOrDelete = */ 1.0 / _options.maxChromosomeLength, }); default: assertThrow(false, solidity::util::Exception, "Invalid Algorithm value."); @@ -114,6 +114,8 @@ unique_ptr FitnessMetricFactory::build( PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), _arguments.count("population") > 0 ? _arguments["population"].as>() : vector{}, @@ -139,6 +141,8 @@ Population PopulationFactory::build( population = move(population) + buildRandom( combinedSize, + _options.minChromosomeLength, + _options.maxChromosomeLength, _fitnessMetric ); @@ -162,14 +166,16 @@ Population PopulationFactory::buildFromStrings( Population PopulationFactory::buildRandom( size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength, shared_ptr _fitnessMetric ) { return Population::makeRandom( move(_fitnessMetric), _populationSize, - MinChromosomeLength, - MaxChromosomeLength + _minChromosomeLength, + _maxChromosomeLength ); } @@ -258,6 +264,16 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value()->value_name("")->default_value(Algorithm::GEWEP), "Algorithm" ) + ( + "min-chromosome-length", + po::value()->value_name("")->default_value(12), + "Minimum length of randomly generated chromosomes." + ) + ( + "max-chromosome-length", + po::value()->value_name("")->default_value(30), + "Maximum length of randomly generated chromosomes." + ) ; keywordDescription.add(algorithmDescription); @@ -360,9 +376,7 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( algorithmOptions, - population.individuals().size(), - PopulationFactory::MinChromosomeLength, - PopulationFactory::MaxChromosomeLength + population.individuals().size() ); AlgorithmRunner algorithmRunner(population, buildAlgorithmRunnerOptions(_arguments), cout); diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 63f570594374..b45a9dd6ebad 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -64,15 +64,15 @@ class GeneticAlgorithmFactory struct Options { Algorithm algorithm; + size_t minChromosomeLength; + size_t maxChromosomeLength; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; static std::unique_ptr build( Options const& _options, - size_t _populationSize, - size_t _minChromosomeLength, - size_t _maxChromosomeLength + size_t _populationSize ); }; @@ -101,11 +101,10 @@ class FitnessMetricFactory class PopulationFactory { public: - static constexpr size_t MinChromosomeLength = 12; - static constexpr size_t MaxChromosomeLength = 30; - struct Options { + size_t minChromosomeLength; + size_t maxChromosomeLength; std::vector population; std::vector randomPopulation; std::vector populationFromFile; @@ -123,6 +122,8 @@ class PopulationFactory ); static Population buildRandom( size_t _populationSize, + size_t _minChromosomeLength, + size_t _maxChromosomeLength, std::shared_ptr _fitnessMetric ); static Population buildFromFile( From b11eff7c88fb8c3d2474196a5c20aad3ca3bb357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 22:53:56 +0100 Subject: [PATCH 070/165] [yul-phaser] Add options for all algorithm-specific parameters --- tools/yulPhaser/Phaser.cpp | 92 +++++++++++++++++++++++++++++++++++--- tools/yulPhaser/Phaser.h | 7 +++ 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 97e4299681bf..b1ee03f56da5 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -64,6 +64,19 @@ GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLi _arguments["algorithm"].as(), _arguments["min-chromosome-length"].as(), _arguments["max-chromosome-length"].as(), + _arguments.count("random-elite-pool-size") > 0 ? + _arguments["random-elite-pool-size"].as() : + optional{}, + _arguments["gewep-mutation-pool-size"].as(), + _arguments["gewep-crossover-pool-size"].as(), + _arguments["gewep-randomisation-chance"].as(), + _arguments["gewep-deletion-vs-addition-chance"].as(), + _arguments.count("gewep-genes-to-randomise") > 0 ? + _arguments["gewep-genes-to-randomise"].as() : + optional{}, + _arguments.count("gewep-genes-to-add-or-delete") > 0 ? + _arguments["gewep-genes-to-add-or-delete"].as() : + optional{}, }; } @@ -77,20 +90,37 @@ unique_ptr GeneticAlgorithmFactory::build( switch (_options.algorithm) { case Algorithm::Random: + { + double elitePoolSize = 1.0 / _populationSize; + + if (_options.randomElitePoolSize.has_value()) + elitePoolSize = _options.randomElitePoolSize.value(); + return make_unique(RandomAlgorithm::Options{ - /* elitePoolSize = */ 1.0 / _populationSize, + /* elitePoolSize = */ elitePoolSize, /* minChromosomeLength = */ _options.minChromosomeLength, /* maxChromosomeLength = */ _options.maxChromosomeLength, }); + } case Algorithm::GEWEP: + { + double percentGenesToRandomise = 1.0 / _options.maxChromosomeLength; + double percentGenesToAddOrDelete = percentGenesToRandomise; + + if (_options.gewepGenesToRandomise.has_value()) + percentGenesToRandomise = _options.gewepGenesToRandomise.value(); + if (_options.gewepGenesToAddOrDelete.has_value()) + percentGenesToAddOrDelete = _options.gewepGenesToAddOrDelete.value(); + return make_unique(GenerationalElitistWithExclusivePools::Options{ - /* mutationPoolSize = */ 0.25, - /* crossoverPoolSize = */ 0.25, - /* randomisationChance = */ 0.9, - /* deletionVsAdditionChance = */ 0.5, - /* percentGenesToRandomise = */ 1.0 / _options.maxChromosomeLength, - /* percentGenesToAddOrDelete = */ 1.0 / _options.maxChromosomeLength, + /* mutationPoolSize = */ _options.gewepMutationPoolSize, + /* crossoverPoolSize = */ _options.gewepCrossoverPoolSize, + /* randomisationChance = */ _options.gewepRandomisationChance, + /* deletionVsAdditionChance = */ _options.gewepDeletionVsAdditionChance, + /* percentGenesToRandomise = */ percentGenesToRandomise, + /* percentGenesToAddOrDelete = */ percentGenesToAddOrDelete, }); + } default: assertThrow(false, solidity::util::Exception, "Invalid Algorithm value."); } @@ -277,6 +307,54 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ; keywordDescription.add(algorithmDescription); + po::options_description gewepAlgorithmDescription("GEWEP ALGORITHM", lineLength, minDescriptionLength); + gewepAlgorithmDescription.add_options() + ( + "gewep-mutation-pool-size", + po::value()->value_name("")->default_value(0.25), + "Percentage of population to regenerate using mutations in each round." + ) + ( + "gewep-crossover-pool-size", + po::value()->value_name("")->default_value(0.25), + "Percentage of population to regenerate using crossover in each round." + ) + ( + "gewep-randomisation-chance", + po::value()->value_name("")->default_value(0.9), + "The chance of choosing gene randomisation as the mutation to perform." + ) + ( + "gewep-deletion-vs-addition-chance", + po::value()->value_name("")->default_value(0.5), + "The chance of choosing gene deletion as the mutation if randomisation was not chosen." + ) + ( + "gewep-genes-to-randomise", + po::value()->value_name(""), + "The chance of any given gene being mutated in gene randomisation. " + "(default=1/max-chromosome-length)" + ) + ( + "gewep-genes-to-add-or-delete", + po::value()->value_name(""), + "The chance of a gene being added (or deleted) in gene addition (or deletion). " + "(default=1/max-chromosome-length)" + ) + ; + keywordDescription.add(gewepAlgorithmDescription); + + po::options_description randomAlgorithmDescription("RANDOM ALGORITHM", lineLength, minDescriptionLength); + randomAlgorithmDescription.add_options() + ( + "random-elite-pool-size", + po::value()->value_name(""), + "Percentage of the population preserved in each round. " + "(default=one individual, regardless of population size)" + ) + ; + keywordDescription.add(randomAlgorithmDescription); + po::options_description populationDescription("POPULATION", lineLength, minDescriptionLength); populationDescription.add_options() ( diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index b45a9dd6ebad..9631aa4cb241 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -66,6 +66,13 @@ class GeneticAlgorithmFactory Algorithm algorithm; size_t minChromosomeLength; size_t maxChromosomeLength; + std::optional randomElitePoolSize; + double gewepMutationPoolSize; + double gewepCrossoverPoolSize; + double gewepRandomisationChance; + double gewepDeletionVsAdditionChance; + std::optional gewepGenesToRandomise; + std::optional gewepGenesToAddOrDelete; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; From 18f0d6eb9420312d1ec587cdefa4c1716cb47b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 00:40:57 +0100 Subject: [PATCH 071/165] [yul-phaser] AlgorithmRunner: Duplicate chromosome randomisation --- test/yulPhaser/AlgorithmRunner.cpp | 49 +++++++++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.cpp | 39 +++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.h | 9 ++++++ tools/yulPhaser/Phaser.cpp | 3 ++ 4 files changed, 100 insertions(+) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 7b20d8db432b..0b54ad38fa2f 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -188,6 +188,55 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_ BOOST_TEST(!fs::exists(m_autosavePath)); } +BOOST_FIXTURE_TEST_CASE(run_should_randomise_duplicate_chromosomes_if_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = true; + m_options.minChromosomeLength = 50; + m_options.maxChromosomeLength = 50; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + auto const& newIndividuals = runner.population().individuals(); + + BOOST_TEST(newIndividuals.size() == 3); + BOOST_TEST(( + newIndividuals[0].chromosome == duplicate || + newIndividuals[1].chromosome == duplicate || + newIndividuals[2].chromosome == duplicate + )); + BOOST_TEST(newIndividuals[0] != newIndividuals[1]); + BOOST_TEST(newIndividuals[0] != newIndividuals[2]); + BOOST_TEST(newIndividuals[1] != newIndividuals[2]); + + BOOST_TEST((newIndividuals[0].chromosome.length() == 50 || newIndividuals[0].chromosome == duplicate)); + BOOST_TEST((newIndividuals[1].chromosome.length() == 50 || newIndividuals[1].chromosome == duplicate)); + BOOST_TEST((newIndividuals[2].chromosome.length() == 50 || newIndividuals[2].chromosome == duplicate)); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_randomise_duplicate_chromosomes_if_not_requested, AlgorithmRunnerFixture) +{ + Chromosome duplicate("afc"); + Population population(m_fitnessMetric, {duplicate, duplicate, duplicate}); + CountingAlgorithm algorithm; + + m_options.maxRounds = 1; + m_options.randomiseDuplicates = false; + AlgorithmRunner runner(population, m_options, m_output); + + runner.run(algorithm); + + BOOST_TEST(runner.population().individuals().size() == 3); + BOOST_TEST(runner.population().individuals()[0].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[1].chromosome == duplicate); + BOOST_TEST(runner.population().individuals()[2].chromosome == duplicate); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index a075fa785ac2..b9f22171b813 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -35,6 +35,7 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { m_population = _algorithm.runNextRound(m_population); + randomiseDuplicates(); m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; m_outputStream << m_population; @@ -64,3 +65,41 @@ void AlgorithmRunner::populationAutosave() const "Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno) ); } + +void AlgorithmRunner::randomiseDuplicates() +{ + if (m_options.randomiseDuplicates) + { + assert(m_options.minChromosomeLength.has_value()); + assert(m_options.maxChromosomeLength.has_value()); + + m_population = randomiseDuplicates( + m_population, + m_options.minChromosomeLength.value(), + m_options.maxChromosomeLength.value() + ); + } +} + +Population AlgorithmRunner::randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength +) +{ + if (_population.individuals().size() == 0) + return _population; + + vector chromosomes{_population.individuals()[0].chromosome}; + size_t duplicateCount = 0; + for (size_t i = 1; i < _population.individuals().size(); ++i) + if (_population.individuals()[i].chromosome == _population.individuals()[i - 1].chromosome) + ++duplicateCount; + else + chromosomes.push_back(_population.individuals()[i].chromosome); + + return ( + Population(_population.fitnessMetric(), chromosomes) + + Population::makeRandom(_population.fitnessMetric(), duplicateCount, _minChromosomeLength, _maxChromosomeLength) + ); +} diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 93c8348d580c..ff0d0e3c3bfc 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -43,6 +43,9 @@ class AlgorithmRunner { std::optional maxRounds = std::nullopt; std::optional populationAutosaveFile = std::nullopt; + bool randomiseDuplicates = false; + std::optional minChromosomeLength = std::nullopt; + std::optional maxChromosomeLength = std::nullopt; }; AlgorithmRunner( @@ -61,6 +64,12 @@ class AlgorithmRunner private: void populationAutosave() const; + void randomiseDuplicates(); + static Population randomiseDuplicates( + Population _population, + size_t _minChromosomeLength, + size_t _maxChromosomeLength + ); Population m_population; Options m_options; diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index b1ee03f56da5..e8902a1bc690 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -438,6 +438,9 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c return { _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt, _arguments.count("population-autosave") > 0 ? static_cast>(_arguments["population-autosave"].as()) : nullopt, + false, + nullopt, + nullopt, }; } From 2563e7a7e308c5b2bd31133a9f14b1795e5243d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 3 Mar 2020 11:04:41 +0100 Subject: [PATCH 072/165] [yul-phaser] Add --no-randomise-duplicates option --- tools/yulPhaser/Phaser.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index e8902a1bc690..7640fbf28f6b 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -294,6 +294,13 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value()->value_name("")->default_value(Algorithm::GEWEP), "Algorithm" ) + ( + "no-randomise-duplicates", + po::bool_switch(), + "By default, after each round of the algorithm duplicate chromosomes are removed from" + "the population and replaced with randomly generated ones. " + "This option disables this postprocessing." + ) ( "min-chromosome-length", po::value()->value_name("")->default_value(12), @@ -438,9 +445,9 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c return { _arguments.count("rounds") > 0 ? static_cast>(_arguments["rounds"].as()) : nullopt, _arguments.count("population-autosave") > 0 ? static_cast>(_arguments["population-autosave"].as()) : nullopt, - false, - nullopt, - nullopt, + !_arguments["no-randomise-duplicates"].as(), + _arguments["min-chromosome-length"].as(), + _arguments["max-chromosome-length"].as(), }; } From 7a1f6a27db5e498dad81f2f3931f21173de73c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 4 Mar 2020 19:46:46 +0100 Subject: [PATCH 073/165] [yul-phaser] More data accessors in metric and algorithm classes --- tools/yulPhaser/FitnessMetrics.h | 3 +++ tools/yulPhaser/GeneticAlgorithms.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 7fac5f0804de..95608e89b056 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -57,6 +57,9 @@ class ProgramSize: public FitnessMetric m_program(std::move(_program)), m_repetitionCount(_repetitionCount) {} + Program const& program() const { return m_program; } + size_t repetitionCount() const { return m_repetitionCount; } + size_t evaluate(Chromosome const& _chromosome) const override; private: diff --git a/tools/yulPhaser/GeneticAlgorithms.h b/tools/yulPhaser/GeneticAlgorithms.h index b9ccb4302c52..a2a7484d674b 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -81,6 +81,8 @@ class RandomAlgorithm: public GeneticAlgorithm assert(_options.isValid()); } + Options const& options() const { return m_options; } + Population runNextRound(Population _population) override; private: @@ -129,6 +131,8 @@ class GenerationalElitistWithExclusivePools: public GeneticAlgorithm assert(_options.isValid()); } + Options const& options() const { return m_options; } + Population runNextRound(Population _population) override; private: From a2821db1dd5d7e9c3b5621d06cabe6aa43cd69cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 4 Mar 2020 19:48:05 +0100 Subject: [PATCH 074/165] [yul-phaser] Phaser: Tests for factories --- test/CMakeLists.txt | 2 + test/yulPhaser/Phaser.cpp | 290 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 test/yulPhaser/Phaser.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d5bf4b686e98..7165a5e272bd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -149,6 +149,7 @@ set(yul_phaser_sources yulPhaser/GeneticAlgorithms.cpp yulPhaser/Mutations.cpp yulPhaser/PairSelections.cpp + yulPhaser/Phaser.cpp yulPhaser/Population.cpp yulPhaser/Program.cpp yulPhaser/Selections.cpp @@ -164,6 +165,7 @@ set(yul_phaser_sources ../tools/yulPhaser/GeneticAlgorithms.cpp ../tools/yulPhaser/Mutations.cpp ../tools/yulPhaser/PairSelections.cpp + ../tools/yulPhaser/Phaser.cpp ../tools/yulPhaser/Population.cpp ../tools/yulPhaser/Program.cpp ../tools/yulPhaser/Selections.cpp diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp new file mode 100644 index 000000000000..26fe3c55effb --- /dev/null +++ b/test/yulPhaser/Phaser.cpp @@ -0,0 +1,290 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include +#include + +#include + +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity::util; +using namespace solidity::langutil; + +namespace fs = boost::filesystem; + +namespace solidity::phaser::test +{ + +class GeneticAlgorithmFactoryFixture +{ +protected: + GeneticAlgorithmFactory::Options m_options = { + /* algorithm = */ Algorithm::Random, + /* minChromosomeLength = */ 50, + /* maxChromosomeLength = */ 100, + /* randomElitePoolSize = */ 0.5, + /* gewepMutationPoolSize = */ 0.1, + /* gewepCrossoverPoolSize = */ 0.1, + /* gewepRandomisationChance = */ 0.6, + /* gewepDeletionVsAdditionChance = */ 0.3, + /* gewepGenesToRandomise = */ 0.4, + /* gewepGenesToAddOrDelete = */ 0.2, + }; +}; + +class FitnessMetricFactoryFixture +{ +protected: + CharStream m_sourceStream = CharStream("{}", ""); + Program m_program = get(Program::load(m_sourceStream)); + FitnessMetricFactory::Options m_options = { + /* chromosomeRepetitions = */ 1, + }; +}; + +class PoulationFactoryFixture +{ +protected: + shared_ptr m_fitnessMetric = make_shared(); + PopulationFactory::Options m_options = { + /* minChromosomeLength = */ 0, + /* maxChromosomeLength = */ 0, + /* population = */ {}, + /* randomPopulation = */ {}, + /* populationFromFile = */ {}, + }; +}; + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(PhaserTest) +BOOST_AUTO_TEST_SUITE(GeneticAlgorithmFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_select_the_right_algorithm_and_pass_the_options_to_it, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::Random; + unique_ptr algorithm1 = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm1 != nullptr); + + auto randomAlgorithm = dynamic_cast(algorithm1.get()); + BOOST_REQUIRE(randomAlgorithm != nullptr); + BOOST_TEST(randomAlgorithm->options().elitePoolSize == m_options.randomElitePoolSize.value()); + BOOST_TEST(randomAlgorithm->options().minChromosomeLength == m_options.minChromosomeLength); + BOOST_TEST(randomAlgorithm->options().maxChromosomeLength == m_options.maxChromosomeLength); + + m_options.algorithm = Algorithm::GEWEP; + unique_ptr algorithm2 = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm2 != nullptr); + + auto gewepAlgorithm = dynamic_cast(algorithm2.get()); + BOOST_REQUIRE(gewepAlgorithm != nullptr); + BOOST_TEST(gewepAlgorithm->options().mutationPoolSize == m_options.gewepMutationPoolSize); + BOOST_TEST(gewepAlgorithm->options().crossoverPoolSize == m_options.gewepCrossoverPoolSize); + BOOST_TEST(gewepAlgorithm->options().randomisationChance == m_options.gewepRandomisationChance); + BOOST_TEST(gewepAlgorithm->options().deletionVsAdditionChance == m_options.gewepDeletionVsAdditionChance); + BOOST_TEST(gewepAlgorithm->options().percentGenesToRandomise == m_options.gewepGenesToRandomise.value()); + BOOST_TEST(gewepAlgorithm->options().percentGenesToAddOrDelete == m_options.gewepGenesToAddOrDelete.value()); +} + +BOOST_FIXTURE_TEST_CASE(build_should_set_random_algorithm_elite_pool_size_based_on_population_size_if_not_specified, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::Random; + m_options.randomElitePoolSize = nullopt; + unique_ptr algorithm = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm != nullptr); + + auto randomAlgorithm = dynamic_cast(algorithm.get()); + BOOST_REQUIRE(randomAlgorithm != nullptr); + BOOST_TEST(randomAlgorithm->options().elitePoolSize == 1.0 / 100.0); +} + +BOOST_FIXTURE_TEST_CASE(build_should_set_gewep_mutation_percentages_based_on_maximum_chromosome_length_if_not_specified, GeneticAlgorithmFactoryFixture) +{ + m_options.algorithm = Algorithm::GEWEP; + m_options.gewepGenesToRandomise = nullopt; + m_options.gewepGenesToAddOrDelete = nullopt; + m_options.maxChromosomeLength = 125; + + unique_ptr algorithm = GeneticAlgorithmFactory::build(m_options, 100); + BOOST_REQUIRE(algorithm != nullptr); + + auto gewepAlgorithm = dynamic_cast(algorithm.get()); + BOOST_REQUIRE(gewepAlgorithm != nullptr); + BOOST_TEST(gewepAlgorithm->options().percentGenesToRandomise == 1.0 / 125.0); + BOOST_TEST(gewepAlgorithm->options().percentGenesToAddOrDelete == 1.0 / 125.0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture) +{ + unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + BOOST_REQUIRE(metric != nullptr); + + auto programSizeMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(programSizeMetric != nullptr); + BOOST_TEST(toString(programSizeMetric->program()) == toString(m_program)); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture) +{ + m_options.chromosomeRepetitions = 5; + unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + BOOST_REQUIRE(metric != nullptr); + + auto programSizeMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(programSizeMetric != nullptr); + BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(PopulationFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_create_an_empty_population_if_no_specific_options_given, PoulationFactoryFixture) +{ + m_options.population = {}; + m_options.randomPopulation = {}; + m_options.populationFromFile = {}; + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, vector{}) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_population_option, PoulationFactoryFixture) +{ + m_options.population = {"a", "afc", "xadd"}; + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, {Chromosome("a"), Chromosome("afc"), Chromosome("xadd")}) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_random_population_option, PoulationFactoryFixture) +{ + m_options.randomPopulation = {5, 3, 2}; + m_options.minChromosomeLength = 5; + m_options.maxChromosomeLength = 10; + + auto population = PopulationFactory::build(m_options, m_fitnessMetric); + + BOOST_TEST(population.individuals().size() == 10); + BOOST_TEST(all_of( + population.individuals().begin(), + population.individuals().end(), + [](auto const& individual){ return 5 <= individual.chromosome.length() && individual.chromosome.length() <= 10; } + )); +} + +BOOST_FIXTURE_TEST_CASE(build_should_respect_population_from_file_option, PoulationFactoryFixture) +{ + map> fileContent = { + {"a.txt", {"a", "fff", "", "jxccLTa"}}, + {"b.txt", {}}, + {"c.txt", {""}}, + {"d.txt", {"c", "T"}}, + }; + + TemporaryDirectory tempDir; + for (auto const& [fileName, chromosomes]: fileContent) + { + ofstream tmpFile(tempDir.memberPath(fileName)); + for (auto const& chromosome: chromosomes) + tmpFile << chromosome << endl; + + m_options.populationFromFile.push_back(tempDir.memberPath(fileName)); + } + + BOOST_TEST( + PopulationFactory::build(m_options, m_fitnessMetric) == + Population(m_fitnessMetric, { + Chromosome("a"), + Chromosome("fff"), + Chromosome(""), + Chromosome("jxccLTa"), + Chromosome(""), + Chromosome("c"), + Chromosome("T"), + }) + ); +} + +BOOST_FIXTURE_TEST_CASE(build_should_throw_FileOpenError_if_population_file_does_not_exist, PoulationFactoryFixture) +{ + m_options.populationFromFile = {"a-file-that-does-not-exist.abcdefgh"}; + assert(!fs::exists(m_options.populationFromFile[0])); + + BOOST_CHECK_THROW(PopulationFactory::build(m_options, m_fitnessMetric), FileOpenError); +} + +BOOST_FIXTURE_TEST_CASE(build_should_combine_populations_from_all_sources, PoulationFactoryFixture) +{ + TemporaryDirectory tempDir; + { + ofstream tmpFile(tempDir.memberPath("population.txt")); + tmpFile << "axc" << endl << "fcL" << endl; + } + + m_options.population = {"axc", "fcL"}; + m_options.randomPopulation = {2}; + m_options.populationFromFile = {tempDir.memberPath("population.txt")}; + m_options.minChromosomeLength = 3; + m_options.maxChromosomeLength = 3; + + auto population = PopulationFactory::build(m_options, m_fitnessMetric); + + auto begin = population.individuals().begin(); + auto end = population.individuals().end(); + BOOST_TEST(population.individuals().size() == 6); + BOOST_TEST(all_of(begin, end, [](auto const& individual){ return individual.chromosome.length() == 3; })); + BOOST_TEST(count(begin, end, Individual(Chromosome("axc"), *m_fitnessMetric)) >= 2); + BOOST_TEST(count(begin, end, Individual(Chromosome("fcL"), *m_fitnessMetric)) >= 2); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(ProgramFactoryTest) + +BOOST_AUTO_TEST_CASE(build_should_load_program_from_file) +{ + TemporaryDirectory tempDir; + { + ofstream tmpFile(tempDir.memberPath("program.yul")); + tmpFile << "{}" << endl; + } + + ProgramFactory::Options options{/* inputFile = */ tempDir.memberPath("program.yul")}; + CharStream expectedProgramSource("{}", ""); + + auto program = ProgramFactory::build(options); + + BOOST_TEST(toString(program) == toString(get(Program::load(expectedProgramSource)))); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} From bdc4d1ccd19561a7a658794075ca068ff4034fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 4 Mar 2020 19:46:18 +0100 Subject: [PATCH 075/165] [yul-phaser] ProgramSize metric: Refactor repeating parts of test code - Also replace test fixture constructor with direct member initialisation --- test/yulPhaser/FitnessMetrics.cpp | 62 ++++++++++++++----------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index ecb628c6be61..e7a389be7e87 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -34,10 +34,6 @@ namespace solidity::phaser::test class FitnessMetricFixture { protected: - FitnessMetricFixture(): - m_sourceStream(SampleSourceCode, ""), - m_program(get(Program::load(m_sourceStream))) {} - static constexpr char SampleSourceCode[] = "{\n" " function foo() -> result\n" @@ -52,8 +48,22 @@ class FitnessMetricFixture " mstore(foo(), bar())\n" "}\n"; - CharStream m_sourceStream; - Program m_program; + Program optimisedProgram(Program _program) const + { + [[maybe_unused]] size_t originalSize = _program.codeSize(); + Program result = move(_program); + result.optimise(m_chromosome.optimisationSteps()); + + // Make sure that the program and the chromosome we have chosen are suitable for the test + assert(result.codeSize() != originalSize); + + return result; + } + + CharStream m_sourceStream = CharStream(SampleSourceCode, ""); + Chromosome m_chromosome{vector{UnusedPruner::name, EquivalentFunctionCombiner::name}}; + Program m_program = get(Program::load(m_sourceStream)); + Program m_optimisedProgram = optimisedProgram(m_program); }; BOOST_AUTO_TEST_SUITE(Phaser) @@ -62,47 +72,32 @@ BOOST_AUTO_TEST_SUITE(ProgramSizeTest) BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, FitnessMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); - - Program optimisedProgram = m_program; - optimisedProgram.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != optimisedProgram.codeSize()); + size_t fitness = ProgramSize(m_program).evaluate(m_chromosome); - BOOST_TEST(ProgramSize(m_program).evaluate(chromosome) != m_program.codeSize()); - BOOST_TEST(ProgramSize(m_program).evaluate(chromosome) == optimisedProgram.codeSize()); + BOOST_TEST(fitness != m_program.codeSize()); + BOOST_TEST(fitness == m_optimisedProgram.codeSize()); } BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, FitnessMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); - - Program programOptimisedOnce = m_program; - programOptimisedOnce.optimise(chromosome.optimisationSteps()); - Program programOptimisedTwice = programOptimisedOnce; - programOptimisedTwice.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != programOptimisedOnce.codeSize()); - assert(m_program.codeSize() != programOptimisedTwice.codeSize()); - assert(programOptimisedOnce.codeSize() != programOptimisedTwice.codeSize()); + Program const& programOptimisedOnce = m_optimisedProgram; + Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); ProgramSize metric(m_program, 2); + size_t fitness = metric.evaluate(m_chromosome); - BOOST_TEST(metric.evaluate(chromosome) != m_program.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) != programOptimisedOnce.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) == programOptimisedTwice.codeSize()); + BOOST_TEST(fitness != m_program.codeSize()); + BOOST_TEST(fitness != programOptimisedOnce.codeSize()); + BOOST_TEST(fitness == programOptimisedTwice.codeSize()); } BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, FitnessMetricFixture) { - Chromosome chromosome(vector{UnusedPruner::name, EquivalentFunctionCombiner::name}); - - Program optimisedProgram = m_program; - optimisedProgram.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != optimisedProgram.codeSize()); - ProgramSize metric(m_program, 0); + size_t fitness = metric.evaluate(m_chromosome); - BOOST_TEST(metric.evaluate(chromosome) == m_program.codeSize()); - BOOST_TEST(metric.evaluate(chromosome) != optimisedProgram.codeSize()); + BOOST_TEST(fitness == m_program.codeSize()); + BOOST_TEST(fitness != m_optimisedProgram.codeSize()); } BOOST_AUTO_TEST_SUITE_END() @@ -110,4 +105,3 @@ BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() } - From 0913fd1aac820637d8f28790124cf908300cedba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 20:47:11 +0100 Subject: [PATCH 076/165] [yul-phaser] Extract ProgramBasedMetric base class from ProgramSize --- test/yulPhaser/FitnessMetrics.cpp | 29 +++++++++++++++++++++++++---- tools/yulPhaser/FitnessMetrics.cpp | 9 +++++++-- tools/yulPhaser/FitnessMetrics.h | 30 +++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index e7a389be7e87..293fac426e25 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -22,16 +22,26 @@ #include +#include + #include using namespace std; using namespace solidity::langutil; +using namespace solidity::util; using namespace solidity::yul; namespace solidity::phaser::test { -class FitnessMetricFixture +class DummyProgramBasedMetric: public ProgramBasedMetric +{ +public: + using ProgramBasedMetric::ProgramBasedMetric; + size_t evaluate(Chromosome const&) const override { return 0; } +}; + +class ProgramBasedMetricFixture { protected: static constexpr char SampleSourceCode[] = @@ -68,9 +78,20 @@ class FitnessMetricFixture BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(FitnessMetricsTest) +BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest) + +BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program, ProgramBasedMetricFixture) +{ + string code = toString(DummyProgramBasedMetric(m_program).optimisedProgram(m_chromosome)); + + BOOST_TEST(code != toString(m_program)); + BOOST_TEST(code == toString(m_optimisedProgram)); +} + +BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ProgramSizeTest) -BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, ProgramBasedMetricFixture) { size_t fitness = ProgramSize(m_program).evaluate(m_chromosome); @@ -78,7 +99,7 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, F BOOST_TEST(fitness == m_optimisedProgram.codeSize()); } -BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) { Program const& programOptimisedOnce = m_optimisedProgram; Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); @@ -91,7 +112,7 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number BOOST_TEST(fitness == programOptimisedTwice.codeSize()); } -BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, FitnessMetricFixture) +BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) { ProgramSize metric(m_program, 0); size_t fitness = metric.evaluate(m_chromosome); diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index be7ea549729e..a3a344eb97b2 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -20,11 +20,16 @@ using namespace std; using namespace solidity::phaser; -size_t ProgramSize::evaluate(Chromosome const& _chromosome) const +Program ProgramBasedMetric::optimisedProgram(Chromosome const& _chromosome) const { Program programCopy = m_program; for (size_t i = 0; i < m_repetitionCount; ++i) programCopy.optimise(_chromosome.optimisationSteps()); - return programCopy.codeSize(); + return programCopy; +} + +size_t ProgramSize::evaluate(Chromosome const& _chromosome) const +{ + return optimisedProgram(_chromosome).codeSize(); } diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 95608e89b056..180fa322c329 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -47,24 +47,44 @@ class FitnessMetric }; /** - * Fitness metric based on the size of a specific program after applying the optimisations from the - * chromosome to it. + * Abstract base class for fitness metrics that return values based on program size. + * + * The class provides utilities for optimising programs according to the information stored in + * chromosomes. + * + * It can also store weights for the @a CodeSize metric. It does not do anything with + * them because it does not actually compute the code size but they are readily available for use + * by derived classes. */ -class ProgramSize: public FitnessMetric +class ProgramBasedMetric: public FitnessMetric { public: - explicit ProgramSize(Program _program, size_t _repetitionCount = 1): + explicit ProgramBasedMetric( + Program _program, + size_t _repetitionCount = 1 + ): m_program(std::move(_program)), m_repetitionCount(_repetitionCount) {} Program const& program() const { return m_program; } size_t repetitionCount() const { return m_repetitionCount; } - size_t evaluate(Chromosome const& _chromosome) const override; + Program optimisedProgram(Chromosome const& _chromosome) const; private: Program m_program; size_t m_repetitionCount; }; +/** + * Fitness metric based on the size of a specific program after applying the optimisations from the + * chromosome to it. + */ +class ProgramSize: public ProgramBasedMetric +{ +public: + using ProgramBasedMetric::ProgramBasedMetric; + size_t evaluate(Chromosome const& _chromosome) const override; +}; + } From 7edbbe4edda845e8032029c19b195fff888a1dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 19:58:14 +0100 Subject: [PATCH 077/165] [yul-phaser] Make FitnessMetric::evaluate() non-const --- test/yulPhaser/FitnessMetrics.cpp | 2 +- test/yulPhaser/TestHelpers.h | 2 +- tools/yulPhaser/FitnessMetrics.cpp | 2 +- tools/yulPhaser/FitnessMetrics.h | 4 ++-- tools/yulPhaser/Population.cpp | 6 +++--- tools/yulPhaser/Population.h | 16 ++++++++-------- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 293fac426e25..8e4b14185dd8 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -38,7 +38,7 @@ class DummyProgramBasedMetric: public ProgramBasedMetric { public: using ProgramBasedMetric::ProgramBasedMetric; - size_t evaluate(Chromosome const&) const override { return 0; } + size_t evaluate(Chromosome const&) override { return 0; } }; class ProgramBasedMetricFixture diff --git a/test/yulPhaser/TestHelpers.h b/test/yulPhaser/TestHelpers.h index aa76ae6da18a..2bf755b18423 100644 --- a/test/yulPhaser/TestHelpers.h +++ b/test/yulPhaser/TestHelpers.h @@ -51,7 +51,7 @@ class ChromosomeLengthMetric: public FitnessMetric { public: using FitnessMetric::FitnessMetric; - size_t evaluate(Chromosome const& _chromosome) const override { return _chromosome.length(); } + size_t evaluate(Chromosome const& _chromosome) override { return _chromosome.length(); } }; // MUTATIONS diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index a3a344eb97b2..0992b9be0a4e 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -29,7 +29,7 @@ Program ProgramBasedMetric::optimisedProgram(Chromosome const& _chromosome) cons return programCopy; } -size_t ProgramSize::evaluate(Chromosome const& _chromosome) const +size_t ProgramSize::evaluate(Chromosome const& _chromosome) { return optimisedProgram(_chromosome).codeSize(); } diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 180fa322c329..b50c26c8e70a 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -43,7 +43,7 @@ class FitnessMetric FitnessMetric& operator=(FitnessMetric const&) = delete; virtual ~FitnessMetric() = default; - virtual size_t evaluate(Chromosome const& _chromosome) const = 0; + virtual size_t evaluate(Chromosome const& _chromosome) = 0; }; /** @@ -84,7 +84,7 @@ class ProgramSize: public ProgramBasedMetric { public: using ProgramBasedMetric::ProgramBasedMetric; - size_t evaluate(Chromosome const& _chromosome) const override; + size_t evaluate(Chromosome const& _chromosome) override; }; } diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index ec63eb3bbe52..87df4e59b4dd 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -59,7 +59,7 @@ bool phaser::isFitter(Individual const& a, Individual const& b) } Population Population::makeRandom( - shared_ptr _fitnessMetric, + shared_ptr _fitnessMetric, size_t _size, function _chromosomeLengthGenerator ) @@ -72,7 +72,7 @@ Population Population::makeRandom( } Population Population::makeRandom( - shared_ptr _fitnessMetric, + shared_ptr _fitnessMetric, size_t _size, size_t _minChromosomeLength, size_t _maxChromosomeLength @@ -145,7 +145,7 @@ ostream& phaser::operator<<(ostream& _stream, Population const& _population) } vector Population::chromosomesToIndividuals( - FitnessMetric const& _fitnessMetric, + FitnessMetric& _fitnessMetric, vector _chromosomes ) { diff --git a/tools/yulPhaser/Population.h b/tools/yulPhaser/Population.h index 29c82efedc17..f8f12632e3c1 100644 --- a/tools/yulPhaser/Population.h +++ b/tools/yulPhaser/Population.h @@ -55,7 +55,7 @@ struct Individual Individual(Chromosome _chromosome, size_t _fitness): chromosome(std::move(_chromosome)), fitness(_fitness) {} - Individual(Chromosome _chromosome, FitnessMetric const& _fitnessMetric): + Individual(Chromosome _chromosome, FitnessMetric& _fitnessMetric): chromosome(std::move(_chromosome)), fitness(_fitnessMetric.evaluate(chromosome)) {} @@ -85,7 +85,7 @@ class Population { public: explicit Population( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, std::vector _chromosomes = {} ): Population( @@ -94,12 +94,12 @@ class Population ) {} static Population makeRandom( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, size_t _size, std::function _chromosomeLengthGenerator ); static Population makeRandom( - std::shared_ptr _fitnessMetric, + std::shared_ptr _fitnessMetric, size_t _size, size_t _minChromosomeLength, size_t _maxChromosomeLength @@ -110,7 +110,7 @@ class Population Population crossover(PairSelection const& _selection, std::function _crossover) const; friend Population (::operator+)(Population _a, Population _b); - std::shared_ptr fitnessMetric() const { return m_fitnessMetric; } + std::shared_ptr fitnessMetric() { return m_fitnessMetric; } std::vector const& individuals() const { return m_individuals; } static size_t uniformChromosomeLength(size_t _min, size_t _max) { return SimulationRNG::uniformInt(_min, _max); } @@ -122,17 +122,17 @@ class Population friend std::ostream& operator<<(std::ostream& _stream, Population const& _population); private: - explicit Population(std::shared_ptr _fitnessMetric, std::vector _individuals): + explicit Population(std::shared_ptr _fitnessMetric, std::vector _individuals): m_fitnessMetric(std::move(_fitnessMetric)), m_individuals{sortedIndividuals(std::move(_individuals))} {} static std::vector chromosomesToIndividuals( - FitnessMetric const& _fitnessMetric, + FitnessMetric& _fitnessMetric, std::vector _chromosomes ); static std::vector sortedIndividuals(std::vector _individuals); - std::shared_ptr m_fitnessMetric; + std::shared_ptr m_fitnessMetric; std::vector m_individuals; }; From 0e03839e6217bb37abdaa0e61c197e9d2f038d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 20 Feb 2020 19:36:46 +0100 Subject: [PATCH 078/165] [yul-phaser] Add RelativeProgramSize metric --- test/yulPhaser/FitnessMetrics.cpp | 52 ++++++++++++++++++++++++++++++ tools/yulPhaser/FitnessMetrics.cpp | 17 ++++++++++ tools/yulPhaser/FitnessMetrics.h | 26 +++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 8e4b14185dd8..27997c791406 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -26,6 +26,8 @@ #include +#include + using namespace std; using namespace solidity::langutil; using namespace solidity::util; @@ -121,6 +123,56 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is BOOST_TEST(fitness != m_optimisedProgram.codeSize()); } +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(RelativeProgramSizeTest) + +BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_the_size_ratio_between_optimised_program_and_original_program, ProgramBasedMetricFixture) +{ + BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize())); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) +{ + Program const& programOptimisedOnce = m_optimisedProgram; + Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); + + RelativeProgramSize metric(m_program, 3, 2); + size_t fitness = metric.evaluate(m_chromosome); + + BOOST_TEST(fitness != 1000); + BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, 3, 1).evaluate(m_chromosome)); + BOOST_TEST(fitness == round(1000.0 * programOptimisedTwice.codeSize() / m_program.codeSize())); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) +{ + RelativeProgramSize metric(m_program, 3, 0); + + BOOST_TEST(metric.evaluate(m_chromosome) == 1000); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_is_zero, ProgramBasedMetricFixture) +{ + CharStream sourceStream = CharStream("{}", ""); + Program program = get(Program::load(sourceStream)); + + RelativeProgramSize metric(program, 3); + + BOOST_TEST(metric.evaluate(m_chromosome) == 1000); + BOOST_TEST(metric.evaluate(Chromosome("")) == 1000); + BOOST_TEST(metric.evaluate(Chromosome("afcxjLTLTDoO")) == 1000); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, ProgramBasedMetricFixture) +{ + double sizeRatio = static_cast(m_optimisedProgram.codeSize()) / m_program.codeSize(); + BOOST_TEST(RelativeProgramSize(m_program, 0).evaluate(m_chromosome) == round(1.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 1).evaluate(m_chromosome) == round(10.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 2).evaluate(m_chromosome) == round(100.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index 0992b9be0a4e..02c3b457ffe0 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -17,6 +17,8 @@ #include +#include + using namespace std; using namespace solidity::phaser; @@ -33,3 +35,18 @@ size_t ProgramSize::evaluate(Chromosome const& _chromosome) { return optimisedProgram(_chromosome).codeSize(); } + +size_t RelativeProgramSize::evaluate(Chromosome const& _chromosome) +{ + size_t const scalingFactor = pow(10, m_fixedPointPrecision); + + size_t unoptimisedSize = optimisedProgram(Chromosome("")).codeSize(); + if (unoptimisedSize == 0) + return scalingFactor; + + size_t optimisedSize = optimisedProgram(_chromosome).codeSize(); + + return static_cast(round( + static_cast(optimisedSize) / unoptimisedSize * scalingFactor + )); +} diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index b50c26c8e70a..3544dba75193 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -87,4 +87,30 @@ class ProgramSize: public ProgramBasedMetric size_t evaluate(Chromosome const& _chromosome) override; }; +/** + * Fitness metric based on the size of a specific program after applying the optimisations from the + * chromosome to it in relation to the original, unoptimised program. + * + * Since metric values are integers, the class multiplies the ratio by 10^@a _fixedPointPrecision + * before rounding it. + */ +class RelativeProgramSize: public ProgramBasedMetric +{ +public: + explicit RelativeProgramSize( + Program _program, + size_t _fixedPointPrecision, + size_t _repetitionCount = 1 + ): + ProgramBasedMetric(std::move(_program), _repetitionCount), + m_fixedPointPrecision(_fixedPointPrecision) {} + + size_t fixedPointPrecision() const { return m_fixedPointPrecision; } + + size_t evaluate(Chromosome const& _chromosome) override; + +private: + size_t m_fixedPointPrecision; +}; + } From e4a360947b6b77e7a2844af0db97048bc282c403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 20:16:47 +0100 Subject: [PATCH 079/165] [yul-phaser] Add FitnessMetricCombination and derived classes for average, sum, min and max --- test/yulPhaser/FitnessMetrics.cpp | 54 ++++++++++++++++++++++++++++ tools/yulPhaser/FitnessMetrics.cpp | 44 +++++++++++++++++++++++ tools/yulPhaser/FitnessMetrics.h | 56 ++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 27997c791406..8b62b03b7e0c 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -78,6 +78,21 @@ class ProgramBasedMetricFixture Program m_optimisedProgram = optimisedProgram(m_program); }; +class FitnessMetricCombinationFixture: public ProgramBasedMetricFixture +{ +protected: + vector> m_simpleMetrics = { + make_shared(m_program, 1), + make_shared(m_program, 2), + make_shared(m_program, 3), + }; + vector m_fitness = { + m_simpleMetrics[0]->evaluate(m_chromosome), + m_simpleMetrics[1]->evaluate(m_chromosome), + m_simpleMetrics[2]->evaluate(m_chromosome), + }; +}; + BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(FitnessMetricsTest) BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest) @@ -173,6 +188,45 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, P BOOST_TEST(RelativeProgramSize(m_program, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); } +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(FitnessMetricCombinationTest) + +BOOST_FIXTURE_TEST_CASE(FitnessMetricAverage_evaluate_should_compute_average_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricAverage metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == (m_fitness[0] + m_fitness[1] + m_fitness[2]) / 3); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricSum_evaluate_should_compute_sum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricSum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == m_fitness[0] + m_fitness[1] + m_fitness[2]); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMaximum_evaluate_should_compute_maximum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMaximum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == max(m_fitness[0], max(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + +BOOST_FIXTURE_TEST_CASE(FitnessMetricMinimum_evaluate_should_compute_minimum_of_values_returned_by_metrics_passed_to_it, FitnessMetricCombinationFixture) +{ + FitnessMetricMinimum metric(m_simpleMetrics); + + assert(m_simpleMetrics.size() == 3); + BOOST_TEST(metric.evaluate(m_chromosome) == min(m_fitness[0], min(m_fitness[1], m_fitness[2]))); + BOOST_TEST(metric.metrics() == m_simpleMetrics); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index 02c3b457ffe0..49482d0afe84 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -50,3 +50,47 @@ size_t RelativeProgramSize::evaluate(Chromosome const& _chromosome) static_cast(optimisedSize) / unoptimisedSize * scalingFactor )); } + +size_t FitnessMetricAverage::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total / m_metrics.size(); +} + +size_t FitnessMetricSum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t total = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + total += m_metrics[i]->evaluate(_chromosome); + + return total; +} + +size_t FitnessMetricMaximum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t maximum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + maximum = max(maximum, m_metrics[i]->evaluate(_chromosome)); + + return maximum; +} + +size_t FitnessMetricMinimum::evaluate(Chromosome const& _chromosome) +{ + assert(m_metrics.size() > 0); + + size_t minimum = m_metrics[0]->evaluate(_chromosome); + for (size_t i = 1; i < m_metrics.size(); ++i) + minimum = min(minimum, m_metrics[i]->evaluate(_chromosome)); + + return minimum; +} diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index 3544dba75193..e79d99ff4c75 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -113,4 +113,60 @@ class RelativeProgramSize: public ProgramBasedMetric size_t m_fixedPointPrecision; }; +/** + * Abstract base class for fitness metrics that compute their value based on values of multiple + * other, nested metrics. + */ +class FitnessMetricCombination: public FitnessMetric +{ +public: + explicit FitnessMetricCombination(std::vector> _metrics): + m_metrics(std::move(_metrics)) {} + + std::vector> const& metrics() const { return m_metrics; } + +protected: + std::vector> m_metrics; +}; + +/** + * Fitness metric that returns the average of values of its nested metrics. + */ +class FitnessMetricAverage: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the sum of values of its nested metrics. + */ +class FitnessMetricSum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the highest of values of its nested metrics. + */ +class FitnessMetricMaximum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + +/** + * Fitness metric that returns the lowest of values of its nested metrics. + */ +class FitnessMetricMinimum: public FitnessMetricCombination +{ +public: + using FitnessMetricCombination::FitnessMetricCombination; + size_t evaluate(Chromosome const& _chromosome) override; +}; + } From 8e64c5c6f058778fc3c89a3ad26c8e0ff52d0570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 18:56:07 +0100 Subject: [PATCH 080/165] [yul-phaser] Add --metric option --- test/yulPhaser/Phaser.cpp | 9 ++++++--- tools/yulPhaser/Phaser.cpp | 32 +++++++++++++++++++++++++++++++- tools/yulPhaser/Phaser.h | 9 +++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index 26fe3c55effb..a99c464daa1a 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -61,6 +61,7 @@ class FitnessMetricFactoryFixture CharStream m_sourceStream = CharStream("{}", ""); Program m_program = get(Program::load(m_sourceStream)); FitnessMetricFactory::Options m_options = { + /* metric = */ MetricChoice::CodeSize, /* chromosomeRepetitions = */ 1, }; }; @@ -141,16 +142,18 @@ BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest) BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture) { + m_options.metric = MetricChoice::RelativeCodeSize; unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); BOOST_REQUIRE(metric != nullptr); - auto programSizeMetric = dynamic_cast(metric.get()); - BOOST_REQUIRE(programSizeMetric != nullptr); - BOOST_TEST(toString(programSizeMetric->program()) == toString(m_program)); + auto relativeProgramSizeMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); + BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_program)); } BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture) { + m_options.metric = MetricChoice::CodeSize; m_options.chromosomeRepetitions = 5; unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); BOOST_REQUIRE(metric != nullptr); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 7640fbf28f6b..e8f2cae50dc2 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -53,10 +53,19 @@ map const AlgorithmToStringMap = }; map const StringToAlgorithmMap = invertMap(AlgorithmToStringMap); +map MetricChoiceToStringMap = +{ + {MetricChoice::CodeSize, "code-size"}, + {MetricChoice::RelativeCodeSize, "relative-code-size"}, +}; +map const StringToMetricChoiceMap = invertMap(MetricChoiceToStringMap); + } istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) { return deserializeChoice(_inputStream, _algorithm, StringToAlgorithmMap); } ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) { return serializeChoice(_outputStream, _algorithm, AlgorithmToStringMap); } +istream& phaser::operator>>(istream& _inputStream, MetricChoice& _metric) { return deserializeChoice(_inputStream, _metric, StringToMetricChoiceMap); } +ostream& phaser::operator<<(ostream& _outputStream, MetricChoice _metric) { return serializeChoice(_outputStream, _metric, MetricChoiceToStringMap); } GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments) { @@ -129,6 +138,7 @@ unique_ptr GeneticAlgorithmFactory::build( FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { + _arguments["metric"].as(), _arguments["chromosome-repetitions"].as(), }; } @@ -138,7 +148,22 @@ unique_ptr FitnessMetricFactory::build( Program _program ) { - return make_unique(move(_program), _options.chromosomeRepetitions); + switch (_options.metric) + { + case MetricChoice::CodeSize: + return make_unique( + move(_program), + _options.chromosomeRepetitions + ); + case MetricChoice::RelativeCodeSize: + return make_unique( + move(_program), + 3, + _options.chromosomeRepetitions + ); + default: + assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value."); + } } PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) @@ -391,6 +416,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::options_description metricsDescription("METRICS", lineLength, minDescriptionLength); metricsDescription.add_options() + ( + "metric", + po::value()->value_name("")->default_value(MetricChoice::CodeSize), + "Metric used to evaluate the fitness of a chromosome." + ) ( "chromosome-repetitions", po::value()->value_name("")->default_value(1), diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 9631aa4cb241..effa2ffe6194 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -52,8 +52,16 @@ enum class Algorithm GEWEP, }; +enum class MetricChoice +{ + CodeSize, + RelativeCodeSize, +}; + std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricChoice& _metric); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::MetricChoice _metric); /** * Builds and validates instances of @a GeneticAlgorithm and its derived classes. @@ -91,6 +99,7 @@ class FitnessMetricFactory public: struct Options { + MetricChoice metric; size_t chromosomeRepetitions; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); From 01050940fd68a23a0453fbe52db2aa5effe0f287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 19:33:54 +0100 Subject: [PATCH 081/165] [yul-phaser] Add --relative-metric-scale option --- test/yulPhaser/Phaser.cpp | 13 +++++++++++++ tools/yulPhaser/Phaser.cpp | 15 ++++++++++++++- tools/yulPhaser/Phaser.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index a99c464daa1a..800301ecfcc7 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -62,6 +62,7 @@ class FitnessMetricFactoryFixture Program m_program = get(Program::load(m_sourceStream)); FitnessMetricFactory::Options m_options = { /* metric = */ MetricChoice::CodeSize, + /* relativeMetricScale = */ 5, /* chromosomeRepetitions = */ 1, }; }; @@ -163,6 +164,18 @@ BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, Fitn BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions); } +BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFactoryFixture) +{ + m_options.metric = MetricChoice::RelativeCodeSize; + m_options.relativeMetricScale = 10; + unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + BOOST_REQUIRE(metric != nullptr); + + auto relativeProgramSizeMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); + BOOST_TEST(relativeProgramSizeMetric->fixedPointPrecision() == m_options.relativeMetricScale); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(PopulationFactoryTest) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index e8f2cae50dc2..a0a787f7f173 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -139,6 +139,7 @@ FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po: { return { _arguments["metric"].as(), + _arguments["relative-metric-scale"].as(), _arguments["chromosome-repetitions"].as(), }; } @@ -158,7 +159,7 @@ unique_ptr FitnessMetricFactory::build( case MetricChoice::RelativeCodeSize: return make_unique( move(_program), - 3, + _options.relativeMetricScale, _options.chromosomeRepetitions ); default: @@ -421,6 +422,18 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value()->value_name("")->default_value(MetricChoice::CodeSize), "Metric used to evaluate the fitness of a chromosome." ) + ( + "relative-metric-scale", + po::value()->value_name("")->default_value(3), + "Scaling factor for values produced by relative fitness metrics. \n" + "Since all metrics must produce integer values, the fractional part of the result is discarded. " + "To keep the numbers meaningful, a relative metric multiples its values by a scaling factor " + "and this option specifies the exponent of this factor. " + "For example with value of 3 the factor is 10^3 = 1000 and the metric will return " + "500 to represent 0.5, 1000 for 1.0, 2000 for 2.0 and so on. " + "Using a bigger factor allows discerning smaller relative differences between chromosomes " + "but makes the numbers less readable and may also lose precision if the numbers are very large." + ) ( "chromosome-repetitions", po::value()->value_name("")->default_value(1), diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index effa2ffe6194..07f1eaea1e0f 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -100,6 +100,7 @@ class FitnessMetricFactory struct Options { MetricChoice metric; + size_t relativeMetricScale; size_t chromosomeRepetitions; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); From bc46323bed66d8cbab49b8d8bc363a2a6e6ccce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 25 Feb 2020 20:31:51 +0100 Subject: [PATCH 082/165] [yul-phaser] Phaser: Accepting multiple input programs - Use average of metric values for individual programs as the overall metric. --- test/yulPhaser/Phaser.cpp | 77 +++++++++++++++++++++++++++++--------- tools/yulPhaser/Phaser.cpp | 68 +++++++++++++++++++++------------ tools/yulPhaser/Phaser.h | 6 +-- 3 files changed, 107 insertions(+), 44 deletions(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index 800301ecfcc7..ea06dd771a21 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -58,8 +58,16 @@ class GeneticAlgorithmFactoryFixture class FitnessMetricFactoryFixture { protected: - CharStream m_sourceStream = CharStream("{}", ""); - Program m_program = get(Program::load(m_sourceStream)); + vector m_sourceStreams = { + CharStream("{}", ""), + CharStream("{{}}", ""), + CharStream("{{{}}}", ""), + }; + vector m_programs = { + get(Program::load(m_sourceStreams[0])), + get(Program::load(m_sourceStreams[1])), + get(Program::load(m_sourceStreams[2])), + }; FitnessMetricFactory::Options m_options = { /* metric = */ MetricChoice::CodeSize, /* relativeMetricScale = */ 5, @@ -144,22 +152,32 @@ BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest) BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture) { m_options.metric = MetricChoice::RelativeCodeSize; - unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); - auto relativeProgramSizeMetric = dynamic_cast(metric.get()); + auto averageMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(averageMetric != nullptr); + BOOST_REQUIRE(averageMetric->metrics().size() == 1); + BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + + auto relativeProgramSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); - BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_program)); + BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_programs[0])); } BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture) { m_options.metric = MetricChoice::CodeSize; m_options.chromosomeRepetitions = 5; - unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); - auto programSizeMetric = dynamic_cast(metric.get()); + auto averageMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(averageMetric != nullptr); + BOOST_REQUIRE(averageMetric->metrics().size() == 1); + BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + + auto programSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); BOOST_REQUIRE(programSizeMetric != nullptr); BOOST_TEST(programSizeMetric->repetitionCount() == m_options.chromosomeRepetitions); } @@ -168,14 +186,29 @@ BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFac { m_options.metric = MetricChoice::RelativeCodeSize; m_options.relativeMetricScale = 10; - unique_ptr metric = FitnessMetricFactory::build(m_options, m_program); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); - auto relativeProgramSizeMetric = dynamic_cast(metric.get()); + auto averageMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(averageMetric != nullptr); + BOOST_REQUIRE(averageMetric->metrics().size() == 1); + BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + + auto relativeProgramSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); BOOST_TEST(relativeProgramSizeMetric->fixedPointPrecision() == m_options.relativeMetricScale); } +BOOST_FIXTURE_TEST_CASE(build_should_create_metric_for_each_input_program, FitnessMetricFactoryFixture) +{ + unique_ptr metric = FitnessMetricFactory::build(m_options, m_programs); + BOOST_REQUIRE(metric != nullptr); + + auto combinedMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(combinedMetric != nullptr); + BOOST_REQUIRE(combinedMetric->metrics().size() == m_programs.size()); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(PopulationFactoryTest) @@ -283,20 +316,30 @@ BOOST_FIXTURE_TEST_CASE(build_should_combine_populations_from_all_sources, Poula BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ProgramFactoryTest) -BOOST_AUTO_TEST_CASE(build_should_load_program_from_file) +BOOST_AUTO_TEST_CASE(build_should_load_programs_from_files) { TemporaryDirectory tempDir; + vector sources{"{}", "{{}}", "{{{}}}"}; + ProgramFactory::Options options{/* inputFiles = */ { + tempDir.memberPath("program1.yul"), + tempDir.memberPath("program2.yul"), + tempDir.memberPath("program3.yul"), + }}; + + for (size_t i = 0; i < sources.size(); ++i) { - ofstream tmpFile(tempDir.memberPath("program.yul")); - tmpFile << "{}" << endl; + ofstream tmpFile(options.inputFiles[i]); + tmpFile << sources[i] << endl; } - ProgramFactory::Options options{/* inputFile = */ tempDir.memberPath("program.yul")}; - CharStream expectedProgramSource("{}", ""); + vector programs = ProgramFactory::build(options); - auto program = ProgramFactory::build(options); - - BOOST_TEST(toString(program) == toString(get(Program::load(expectedProgramSource)))); + BOOST_TEST(programs.size() == sources.size()); + for (size_t i = 0; i < sources.size(); ++i) + { + CharStream sourceStream(sources[i], options.inputFiles[i]); + BOOST_TEST(toString(programs[i]) == toString(get(Program::load(sourceStream)))); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index a0a787f7f173..d0d9d9a1e56d 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -146,25 +146,39 @@ FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po: unique_ptr FitnessMetricFactory::build( Options const& _options, - Program _program + vector _programs ) { + assert(_programs.size() > 0 && "Validations should prevent this from being executed with zero files."); + + vector> metrics; switch (_options.metric) { case MetricChoice::CodeSize: - return make_unique( - move(_program), - _options.chromosomeRepetitions - ); + { + for (Program& program: _programs) + metrics.push_back(make_unique( + move(program), + _options.chromosomeRepetitions + )); + + break; + } case MetricChoice::RelativeCodeSize: - return make_unique( - move(_program), - _options.relativeMetricScale, - _options.chromosomeRepetitions - ); + { + for (Program& program: _programs) + metrics.push_back(make_unique( + move(program), + _options.relativeMetricScale, + _options.chromosomeRepetitions + )); + break; + } default: assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value."); } + + return make_unique(move(metrics)); } PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) @@ -246,20 +260,26 @@ Population PopulationFactory::buildFromFile( ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { - _arguments["input-file"].as(), + _arguments["input-files"].as>(), }; } -Program ProgramFactory::build(Options const& _options) +vector ProgramFactory::build(Options const& _options) { - CharStream sourceCode = loadSource(_options.inputFile); - variant programOrErrors = Program::load(sourceCode); - if (holds_alternative(programOrErrors)) + vector inputPrograms; + for (auto& path: _options.inputFiles) { - cerr << get(programOrErrors) << endl; - assertThrow(false, InvalidProgram, "Failed to load program " + _options.inputFile); + CharStream sourceCode = loadSource(path); + variant programOrErrors = Program::load(sourceCode); + if (holds_alternative(programOrErrors)) + { + cerr << get(programOrErrors) << endl; + assertThrow(false, InvalidProgram, "Failed to load program " + path); + } + inputPrograms.push_back(move(get(programOrErrors))); } - return move(get(programOrErrors)); + + return inputPrograms; } CharStream ProgramFactory::loadSource(string const& _sourcePath) @@ -303,7 +323,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::options_description generalDescription("GENERAL", lineLength, minDescriptionLength); generalDescription.add_options() ("help", "Show help message and exit.") - ("input-file", po::value()->required()->value_name(""), "Input file.") + ("input-files", po::value>()->required()->value_name(""), "Input files.") ("seed", po::value()->value_name(""), "Seed for the random number generator.") ( "rounds", @@ -443,7 +463,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() keywordDescription.add(metricsDescription); po::positional_options_description positionalDescription; - positionalDescription.add("input-file", 1); + positionalDescription.add("input-files", -1); return {keywordDescription, positionalDescription}; } @@ -465,8 +485,8 @@ optional Phaser::parseCommandLine(int _argc, char** _argv) return nullopt; } - if (arguments.count("input-file") == 0) - assertThrow(false, NoInputFiles, "Missing argument: input-file."); + if (arguments.count("input-files") == 0) + assertThrow(false, NoInputFiles, "Missing argument: input-files."); return arguments; } @@ -501,8 +521,8 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments); auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); - Program program = ProgramFactory::build(programOptions); - unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(program)); + vector programs = ProgramFactory::build(programOptions); + unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs)); Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 07f1eaea1e0f..55c808f07baa 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -108,7 +108,7 @@ class FitnessMetricFactory static std::unique_ptr build( Options const& _options, - Program _program + std::vector _programs ); }; @@ -157,12 +157,12 @@ class ProgramFactory public: struct Options { - std::string inputFile; + std::vector inputFiles; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; - static Program build(Options const& _options); + static std::vector build(Options const& _options); private: static langutil::CharStream loadSource(std::string const& _sourcePath); From d86652cb9618907b70ec4c1039b3dabf53219a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 16:32:49 +0100 Subject: [PATCH 083/165] [yul-phaser] Add --metric-aggregator option --- test/yulPhaser/Phaser.cpp | 14 +++++++++----- tools/yulPhaser/Phaser.cpp | 32 +++++++++++++++++++++++++++++++- tools/yulPhaser/Phaser.h | 11 +++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index ea06dd771a21..aab34db61734 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -70,6 +70,7 @@ class FitnessMetricFactoryFixture }; FitnessMetricFactory::Options m_options = { /* metric = */ MetricChoice::CodeSize, + /* metricAggregator = */ MetricAggregatorChoice::Average, /* relativeMetricScale = */ 5, /* chromosomeRepetitions = */ 1, }; @@ -152,15 +153,16 @@ BOOST_AUTO_TEST_SUITE(FitnessMetricFactoryTest) BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMetricFactoryFixture) { m_options.metric = MetricChoice::RelativeCodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Sum; unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); - auto averageMetric = dynamic_cast(metric.get()); - BOOST_REQUIRE(averageMetric != nullptr); - BOOST_REQUIRE(averageMetric->metrics().size() == 1); - BOOST_REQUIRE(averageMetric->metrics()[0] != nullptr); + auto sumMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(sumMetric != nullptr); + BOOST_REQUIRE(sumMetric->metrics().size() == 1); + BOOST_REQUIRE(sumMetric->metrics()[0] != nullptr); - auto relativeProgramSizeMetric = dynamic_cast(averageMetric->metrics()[0].get()); + auto relativeProgramSizeMetric = dynamic_cast(sumMetric->metrics()[0].get()); BOOST_REQUIRE(relativeProgramSizeMetric != nullptr); BOOST_TEST(toString(relativeProgramSizeMetric->program()) == toString(m_programs[0])); } @@ -168,6 +170,7 @@ BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMet BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, FitnessMetricFactoryFixture) { m_options.metric = MetricChoice::CodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Average; m_options.chromosomeRepetitions = 5; unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); @@ -185,6 +188,7 @@ BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, Fitn BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFactoryFixture) { m_options.metric = MetricChoice::RelativeCodeSize; + m_options.metricAggregator = MetricAggregatorChoice::Average; m_options.relativeMetricScale = 10; unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); BOOST_REQUIRE(metric != nullptr); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index d0d9d9a1e56d..c62b62dc3f8a 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -60,12 +60,23 @@ map MetricChoiceToStringMap = }; map const StringToMetricChoiceMap = invertMap(MetricChoiceToStringMap); +map const MetricAggregatorChoiceToStringMap = +{ + {MetricAggregatorChoice::Average, "average"}, + {MetricAggregatorChoice::Sum, "sum"}, + {MetricAggregatorChoice::Maximum, "maximum"}, + {MetricAggregatorChoice::Minimum, "minimum"}, +}; +map const StringToMetricAggregatorChoiceMap = invertMap(MetricAggregatorChoiceToStringMap); + } istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) { return deserializeChoice(_inputStream, _algorithm, StringToAlgorithmMap); } ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) { return serializeChoice(_outputStream, _algorithm, AlgorithmToStringMap); } istream& phaser::operator>>(istream& _inputStream, MetricChoice& _metric) { return deserializeChoice(_inputStream, _metric, StringToMetricChoiceMap); } ostream& phaser::operator<<(ostream& _outputStream, MetricChoice _metric) { return serializeChoice(_outputStream, _metric, MetricChoiceToStringMap); } +istream& phaser::operator>>(istream& _inputStream, MetricAggregatorChoice& _aggregator) { return deserializeChoice(_inputStream, _aggregator, StringToMetricAggregatorChoiceMap); } +ostream& phaser::operator<<(ostream& _outputStream, MetricAggregatorChoice _aggregator) { return serializeChoice(_outputStream, _aggregator, MetricAggregatorChoiceToStringMap); } GeneticAlgorithmFactory::Options GeneticAlgorithmFactory::Options::fromCommandLine(po::variables_map const& _arguments) { @@ -139,6 +150,7 @@ FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po: { return { _arguments["metric"].as(), + _arguments["metric-aggregator"].as(), _arguments["relative-metric-scale"].as(), _arguments["chromosome-repetitions"].as(), }; @@ -178,7 +190,19 @@ unique_ptr FitnessMetricFactory::build( assertThrow(false, solidity::util::Exception, "Invalid MetricChoice value."); } - return make_unique(move(metrics)); + switch (_options.metricAggregator) + { + case MetricAggregatorChoice::Average: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Sum: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Maximum: + return make_unique(move(metrics)); + case MetricAggregatorChoice::Minimum: + return make_unique(move(metrics)); + default: + assertThrow(false, solidity::util::Exception, "Invalid MetricAggregatorChoice value."); + } } PopulationFactory::Options PopulationFactory::Options::fromCommandLine(po::variables_map const& _arguments) @@ -442,6 +466,12 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value()->value_name("")->default_value(MetricChoice::CodeSize), "Metric used to evaluate the fitness of a chromosome." ) + ( + "metric-aggregator", + po::value()->value_name("")->default_value(MetricAggregatorChoice::Average), + "Operator used to combine multiple fitness metric obtained by evaluating a chromosome " + "separately for each input program." + ) ( "relative-metric-scale", po::value()->value_name("")->default_value(3), diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 55c808f07baa..2e72c31f661e 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -58,10 +58,20 @@ enum class MetricChoice RelativeCodeSize, }; +enum class MetricAggregatorChoice +{ + Average, + Sum, + Maximum, + Minimum, +}; + std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricChoice& _metric); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::MetricChoice _metric); +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricAggregatorChoice& _aggregator); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::MetricAggregatorChoice _aggregator); /** * Builds and validates instances of @a GeneticAlgorithm and its derived classes. @@ -100,6 +110,7 @@ class FitnessMetricFactory struct Options { MetricChoice metric; + MetricAggregatorChoice metricAggregator; size_t relativeMetricScale; size_t chromosomeRepetitions; From 905147321b7896508108060d00aa2dd51f58ccf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 00:12:54 +0100 Subject: [PATCH 084/165] [yul-phaser] Phaser: Change default metric to RelativeCodeSize --- tools/yulPhaser/Phaser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index c62b62dc3f8a..da0296eff0a8 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -463,7 +463,7 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() metricsDescription.add_options() ( "metric", - po::value()->value_name("")->default_value(MetricChoice::CodeSize), + po::value()->value_name("")->default_value(MetricChoice::RelativeCodeSize), "Metric used to evaluate the fitness of a chromosome." ) ( From 23d00b5ca3b6217fcbe83014f65c3fef5384e819 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 9 Mar 2020 16:14:07 -0500 Subject: [PATCH 085/165] Extracted 292 tests from SolidityEndToEndTest.cpp --- test/libsolidity/SolidityEndToEndTest.cpp | 13284 ++++------------ .../extracted/abi_decode_dynamic_array.sol | 8 + .../extracted/abi_decode_static_array.sol | 12 + .../extracted/abi_decode_static_array_v2.sol | 15 + .../extracted/abi_decode_trivial.sol | 8 + .../semanticTests/extracted/abi_decode_v2.sol | 22 + .../extracted/abi_decode_v2_calldata.sol | 16 + .../extracted/abi_decode_v2_storage.sol | 24 + .../semanticTests/extracted/abi_encode.sol | 36 + .../extracted/abi_encode_call.sol | 26 + .../extracted/abi_encode_decode_simple.sol | 9 + .../extracted/abi_encode_empty_string_v2.sol | 13 + .../extracted/abi_encode_rational.sol | 9 + .../extracted/abi_encode_rational_v2.sol | 12 + .../semanticTests/extracted/abi_encode_v2.sol | 53 + .../extracted/access_base_storage.sol | 30 + .../accessor_for_const_state_variable.sol | 6 + .../extracted/accessor_for_state_variable.sol | 8 + .../semanticTests/extracted/addmod_mulmod.sol | 12 + .../extracted/addmod_mulmod_zero.sol | 24 + .../extracted/address_overload_resolution.sol | 24 + .../array_copy_different_packing.sol | 21 + .../extracted/array_copy_nested_array.sol | 15 + .../array_copy_storage_abi_signed.sol | 20 + ...ay_copy_storage_storage_static_dynamic.sol | 14 + ...ray_copy_storage_storage_static_static.sol | 17 + .../extracted/array_copy_target_leftover2.sol | 22 + .../extracted/array_copy_target_simple.sol | 21 + .../semanticTests/extracted/array_pop.sol | 16 + .../extracted/array_pop_empty_exception.sol | 11 + .../extracted/array_pop_isolated.sol | 13 + .../semanticTests/extracted/array_push.sol | 19 + .../extracted/array_push_packed_array.sol | 16 + .../extracted/array_push_struct.sol | 23 + .../extracted/assert_require.sol | 24 + ...ment_to_const_var_involving_expression.sol | 10 + .../semanticTests/extracted/balance.sol | 13 + ...base_access_to_function_type_variables.sol | 21 + .../extracted/base_constructor_arguments.sol | 24 + .../extracted/break_in_modifier.sol | 20 + .../extracted/byte_array_pop.sol | 17 + .../extracted/byte_array_pop_copy_long.sol | 12 + .../byte_array_pop_empty_exception.sol | 14 + .../extracted/byte_array_pop_isolated.sol | 13 + .../extracted/byte_array_pop_masking_long.sol | 12 + .../extracted/byte_array_push.sol | 18 + .../extracted/byte_array_push_transition.sol | 18 + .../extracted/byte_optimization_bug.sol | 19 + .../extracted/bytes_delete_element.sol | 19 + .../extracted/bytes_length_member.sol | 17 + .../call_function_returning_function.sol | 28 + .../extracted/calldata_array.sol | 16 + .../calldata_array_dynamic_invalid.sol | 21 + ...ta_array_dynamic_invalid_static_middle.sol | 30 + .../extracted/calldata_array_of_struct.sol | 24 + .../calldata_array_of_struct_to_memory.sol | 25 + .../calldata_dynamic_array_to_memory.sol | 15 + .../extracted/calldata_struct.sol | 17 + .../extracted/calldata_struct_and_ints.sol | 20 + .../calldata_struct_array_member.sol | 24 + .../extracted/calldata_struct_to_memory.sol | 17 + .../extracted/calldata_structs.sol | 27 + .../calling_nonexisting_contract_throws.sol | 28 + .../calling_uninitialized_function.sol | 17 + ...lling_uninitialized_function_in_detail.sol | 20 + ...g_uninitialized_function_through_array.sol | 20 + .../cleanup_address_types_shortening.sol | 33 + .../cleanup_bytes_types_shortening.sol | 15 + .../extracted/cleanup_in_compound_assign.sol | 13 + .../extracted/code_access_content.sol | 42 + .../extracted/code_access_create.sol | 26 + .../extracted/code_access_padding.sol | 19 + .../extracted/constant_string.sol | 22 + .../constant_var_as_array_length.sol | 14 + .../extracted/constant_variables.sol | 11 + .../constructing_enums_from_ints.sol | 12 + .../constructor_arguments_external.sol | 22 + .../constructor_arguments_internal.sol | 38 + .../constructor_static_array_argument.sol | 16 + .../extracted/continue_in_modifier.sol | 20 + .../contract_binary_dependencies.sol | 20 + .../extracted/copy_function_storage_array.sol | 18 + ...opy_internal_function_array_to_storage.sol | 22 + .../crazy_elementary_typenames_on_stack.sol | 15 + .../create_dynamic_array_with_zero_length.sol | 9 + .../extracted/create_memory_array.sol | 21 + .../create_multiple_dynamic_arrays.sol | 34 + .../extracted/cross_contract_types.sol | 17 + .../semanticTests/extracted/decayed_tuple.sol | 10 + .../extracted/delete_on_array_of_structs.sol | 20 + .../derived_overload_base_function_direct.sol | 21 + ...erived_overload_base_function_indirect.sol | 29 + .../extracted/destructuring_assignment.sol | 36 + .../extracted/divisiod_by_zero.sol | 15 + .../extracted/dynamic_arrays_in_storage.sol | 53 + .../dynamic_out_of_bounds_array_access.sol | 34 + .../extracted/empty_name_return_parameter.sol | 10 + .../extracted/enum_explicit_overflow.sol | 31 + ...vm_exceptions_in_constructor_call_fail.sol | 19 + .../evm_exceptions_out_of_band_access.sol | 19 + .../semanticTests/extracted/exp_cleanup.sol | 9 + .../extracted/exp_cleanup_direct.sol | 8 + .../extracted/exp_cleanup_nonzero_base.sol | 8 + .../extracted/explicit_base_class.sol | 27 + .../extracted/external_function.sol | 18 + .../extracted/external_public_override.sol | 22 + .../extracted/external_types_in_calls.sol | 28 + .../extracted/fixed_arrays_as_return_type.sol | 21 + .../fixed_arrays_in_constructors.sol | 14 + .../extracted/fixed_bytes_length_access.sol | 10 + .../fixed_out_of_bounds_array_access.sol | 28 + .../extracted/flipping_sign_tests.sol | 10 + .../extracted/function_array_cross_calls.sol | 45 + .../extracted/function_delete_stack.sol | 16 + .../extracted/function_delete_storage.sol | 27 + .../extracted/function_memory_array.sol | 40 + .../extracted/function_modifier.sol | 13 + ..._calling_functions_in_creation_context.sol | 49 + .../function_modifier_for_constructor.sol | 27 + .../extracted/function_modifier_library.sol | 28 + .../function_modifier_library_inheritance.sol | 34 + .../function_modifier_local_variables.sol | 19 + .../extracted/function_modifier_loop.sol | 13 + .../function_modifier_multi_invocation.sol | 14 + .../function_modifier_multi_with_return.sol | 17 + .../function_modifier_multiple_times.sol | 15 + ...ion_modifier_multiple_times_local_vars.sol | 18 + .../function_modifier_overriding.sol | 19 + .../function_type_library_internal.sol | 26 + ...unction_usage_in_constructor_arguments.sol | 24 + .../functions_called_by_constructor.sol | 21 + .../extracted/gas_and_value_basic.sol | 44 + .../extracted/gas_and_value_brace_syntax.sol | 43 + .../extracted/gasleft_decrease.sol | 20 + .../extracted/gasleft_shadow_resolution.sol | 14 + .../inherited_constant_state_var.sol | 13 + .../extracted/inherited_function.sol | 19 + ...d_function_calldata_calldata_interface.sol | 25 + .../inherited_function_calldata_memory.sol | 22 + ...ted_function_calldata_memory_interface.sol | 25 + .../inherited_function_from_a_library.sol | 19 + .../inline_array_index_access_ints.sol | 8 + .../inline_array_index_access_strings.sol | 15 + .../extracted/inline_array_return.sol | 15 + .../extracted/inline_array_singleton.sol | 9 + ...rray_storage_to_memory_conversion_ints.sol | 11 + ...y_storage_to_memory_conversion_strings.sol | 12 + .../inline_array_strings_from_document.sol | 12 + ...inline_assembly_embedded_function_call.sol | 27 + .../extracted/inline_assembly_for.sol | 26 + .../extracted/inline_assembly_for2.sol | 29 + .../inline_assembly_function_call.sol | 21 + .../inline_assembly_function_call2.sol | 24 + ...line_assembly_function_call_assignment.sol | 23 + .../extracted/inline_assembly_if.sol | 17 + .../inline_assembly_in_modifiers.sol | 19 + .../inline_assembly_memory_access.sol | 13 + .../inline_assembly_read_and_write_stack.sol | 13 + .../extracted/inline_assembly_recursion.sol | 28 + .../inline_assembly_storage_access.sol | 22 + ...ssembly_storage_access_inside_function.sol | 23 + ...ne_assembly_storage_access_via_pointer.sol | 25 + .../extracted/inline_assembly_switch.sol | 24 + .../inline_assembly_write_to_stack.sol | 13 + .../extracted/inline_member_init.sol | 19 + .../inline_member_init_inheritence.sol | 24 + ...r_init_inheritence_without_constructor.sol | 20 + .../inline_tuple_with_rational_numbers.sol | 9 + .../extracted/inlineasm_empty_let.sol | 15 + .../extracted/internal_library_function.sol | 21 + .../internal_library_function_bound.sol | 26 + ...ernal_library_function_calling_private.sol | 26 + ...ernal_library_function_return_var_size.sol | 26 + .../invalid_enum_as_external_arg.sol | 20 + .../invalid_enum_as_external_ret.sol | 32 + .../extracted/invalid_enum_compared.sol | 29 + .../extracted/invalid_enum_stored.sol | 23 + .../extracted/invalid_instruction.sol | 12 + .../extracted/iszero_bnot_correct.sol | 19 + .../extracted/keccak256_assembly.sol | 12 + .../extracted/keccak256_empty.sol | 10 + .../extracted/keccak256_with_bytes.sol | 13 + .../library_enum_as_an_expression.sol | 14 + .../library_struct_as_an_expression.sol | 17 + .../extracted/literal_empty_string.sol | 20 + .../extracted/lone_struct_array_type.sol | 16 + .../extracted/mapping_of_functions.sol | 34 + .../memory_arrays_of_various_sizes.sol | 17 + .../extracted/memory_overwrite.sol | 10 + .../memory_structs_as_function_args.sol | 32 + .../extracted/memory_structs_nested.sol | 42 + .../extracted/memory_structs_read_write.sol | 56 + .../memory_structs_with_mappings.sol | 24 + .../extracted/multi_variable_declaration.sol | 47 + .../extracted/negative_stack_height.sol | 63 + .../extracted/nested_calldata_struct.sol | 26 + .../nested_calldata_struct_to_memory.sol | 27 + ...rloaded_function_call_resolve_to_first.sol | 18 + ...loaded_function_call_resolve_to_second.sol | 18 + .../overloaded_function_call_with_if_else.sol | 20 + .../extracted/packed_functions.sol | 48 + .../extracted/packed_storage_overflow.sol | 16 + .../extracted/packed_storage_signed.sol | 22 + .../packed_storage_structs_bytes.sol | 45 + .../extracted/packed_storage_structs_enum.sol | 33 + .../extracted/packed_storage_structs_uint.sol | 30 + .../pass_dynamic_arguments_to_the_base.sol | 18 + ...ass_dynamic_arguments_to_the_base_base.sol | 23 + ...ic_arguments_to_the_base_base_with_gap.sol | 23 + .../pass_function_types_externally.sol | 21 + .../pass_function_types_internally.sol | 16 + .../extracted/payable_constructor.sol | 8 + .../extracted/positive_integers_to_signed.sol | 10 + .../extracted/recursive_structs.sol | 19 + .../return_does_not_skip_modifier.sol | 16 + .../extracted/return_in_modifier.sol | 20 + .../semanticTests/extracted/revert.sol | 21 + .../extracted/ripemd160_empty.sol | 8 + ...e_function_in_construction_and_runtime.sol | 19 + ...onstruction_and_runtime_equality_check.sol | 18 + .../extracted/scientific_notation.sol | 36 + .../extracted/send_zero_ether.sol | 19 + .../extracted/senders_balance.sol | 20 + .../semanticTests/extracted/sha256_empty.sol | 8 + .../semanticTests/extracted/shift_cleanup.sol | 11 + .../extracted/shift_cleanup_garbled.sol | 11 + .../extracted/shift_constant_left.sol | 6 + .../shift_constant_left_assignment.sol | 9 + .../extracted/shift_constant_right.sol | 6 + .../shift_constant_right_assignment.sol | 9 + .../semanticTests/extracted/shift_left.sol | 13 + .../extracted/shift_left_assignment.sol | 14 + .../shift_left_assignment_different_type.sol | 13 + .../extracted/shift_left_larger_type.sol | 11 + .../extracted/shift_left_uint32.sol | 12 + .../extracted/shift_left_uint8.sol | 9 + .../shift_negative_constant_left.sol | 6 + .../shift_negative_constant_right.sol | 6 + .../extracted/shift_negative_rvalue.sol | 13 + .../shift_negative_rvalue_assignment.sol | 15 + .../extracted/shift_overflow.sol | 16 + .../semanticTests/extracted/shift_right.sol | 12 + .../extracted/shift_right_assignment.sol | 12 + .../shift_right_assignment_signed.sol | 12 + .../shift_right_negative_literal.sol | 65 + .../extracted/shift_right_negative_lvalue.sol | 19 + ...shift_right_negative_lvalue_assignment.sol | 20 + .../shift_right_negative_lvalue_int16.sol | 19 + .../shift_right_negative_lvalue_int32.sol | 19 + .../shift_right_negative_lvalue_int8.sol | 19 + .../extracted/shift_right_uint32.sol | 11 + .../extracted/shift_right_uint8.sol | 9 + .../simple_constant_variables_test.sol | 10 + .../semanticTests/extracted/simple_throw.sol | 11 + .../single_copy_with_multiple_inheritance.sol | 35 + .../extracted/skip_dynamic_types.sol | 15 + .../skip_dynamic_types_for_structs.sol | 22 + .../stacked_return_with_modifiers.sol | 20 + .../state_variable_local_variable_mixture.sol | 11 + .../state_variable_under_contract_name.sol | 10 + .../extracted/storage_array_ref.sol | 60 + ...string_as_mapping_key_without_variable.sol | 11 + .../semanticTests/extracted/store_bytes.sol | 14 + .../extracted/store_function.sol | 28 + .../store_function_in_constructor.sol | 21 + ...nternal_unused_function_in_constructor.sol | 18 + ...unused_library_function_in_constructor.sol | 21 + .../semanticTests/extracted/string_tuples.sol | 17 + .../struct_assign_reference_to_struct.sol | 36 + .../semanticTests/extracted/struct_copy.sol | 48 + .../extracted/struct_copy_via_local.sol | 19 + .../extracted/struct_delete_member.sol | 20 + .../struct_delete_struct_in_mapping.sol | 18 + .../extracted/struct_named_constructor.sol | 14 + .../semanticTests/extracted/super.sol | 29 + .../semanticTests/extracted/super_alone.sol | 10 + .../extracted/super_in_constructor.sol | 35 + .../extracted/super_overload.sol | 27 + .../extracted/swap_in_storage_overwrite.sol | 34 + .../extracted/test_underscore_in_hex.sol | 11 + .../semanticTests/extracted/tuples.sol | 30 + .../typed_multi_variable_declaration.sol | 26 + ...ialized_internal_storage_function_call.sol | 11 + ...ract_enums_with_explicit_contract_name.sol | 10 + .../semanticTests/extracted/using_enums.sol | 16 + .../extracted/using_inherited_enum.sol | 13 + .../using_inherited_enum_excplicitly.sol | 13 + .../semanticTests/extracted/value_complex.sol | 23 + .../extracted/value_for_constructor.sol | 45 + .../semanticTests/extracted/value_insane.sol | 22 + .../extracted/virtual_function_calls.sol | 22 + ...unction_usage_in_constructor_arguments.sol | 32 + .../extracted/write_storage_external.sol | 40 + 293 files changed, 9477 insertions(+), 9818 deletions(-) create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_call.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_rational.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/access_base_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol create mode 100644 test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol create mode 100644 test/libsolidity/semanticTests/extracted/addmod_mulmod.sol create mode 100644 test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol create mode 100644 test/libsolidity/semanticTests/extracted/address_overload_resolution.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_pop.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_pop_isolated.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_push.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_push_packed_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/array_push_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/assert_require.sol create mode 100644 test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol create mode 100644 test/libsolidity/semanticTests/extracted/balance.sol create mode 100644 test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol create mode 100644 test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol create mode 100644 test/libsolidity/semanticTests/extracted/break_in_modifier.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_pop.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_push.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol create mode 100644 test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol create mode 100644 test/libsolidity/semanticTests/extracted/bytes_delete_element.sol create mode 100644 test/libsolidity/semanticTests/extracted/bytes_length_member.sol create mode 100644 test/libsolidity/semanticTests/extracted/call_function_returning_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_structs.sol create mode 100644 test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol create mode 100644 test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol create mode 100644 test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol create mode 100644 test/libsolidity/semanticTests/extracted/code_access_content.sol create mode 100644 test/libsolidity/semanticTests/extracted/code_access_create.sol create mode 100644 test/libsolidity/semanticTests/extracted/code_access_padding.sol create mode 100644 test/libsolidity/semanticTests/extracted/constant_string.sol create mode 100644 test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol create mode 100644 test/libsolidity/semanticTests/extracted/constant_variables.sol create mode 100644 test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol create mode 100644 test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol create mode 100644 test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol create mode 100644 test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol create mode 100644 test/libsolidity/semanticTests/extracted/continue_in_modifier.sol create mode 100644 test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol create mode 100644 test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol create mode 100644 test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol create mode 100644 test/libsolidity/semanticTests/extracted/create_memory_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol create mode 100644 test/libsolidity/semanticTests/extracted/cross_contract_types.sol create mode 100644 test/libsolidity/semanticTests/extracted/decayed_tuple.sol create mode 100644 test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol create mode 100644 test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol create mode 100644 test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol create mode 100644 test/libsolidity/semanticTests/extracted/destructuring_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol create mode 100644 test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol create mode 100644 test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol create mode 100644 test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol create mode 100644 test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/exp_cleanup.sol create mode 100644 test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol create mode 100644 test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol create mode 100644 test/libsolidity/semanticTests/extracted/explicit_base_class.sol create mode 100644 test/libsolidity/semanticTests/extracted/external_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/external_public_override.sol create mode 100644 test/libsolidity/semanticTests/extracted/external_types_in_calls.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_delete_stack.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_delete_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_memory_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_library.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_loop.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_type_library_internal.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol create mode 100644 test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol create mode 100644 test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol create mode 100644 test/libsolidity/semanticTests/extracted/gasleft_decrease.sol create mode 100644 test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol create mode 100644 test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_return.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_singleton.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_for.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_if.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_member_init.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol create mode 100644 test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol create mode 100644 test/libsolidity/semanticTests/extracted/internal_library_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol create mode 100644 test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol create mode 100644 test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol create mode 100644 test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol create mode 100644 test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol create mode 100644 test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol create mode 100644 test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol create mode 100644 test/libsolidity/semanticTests/extracted/invalid_instruction.sol create mode 100644 test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_assembly.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_empty.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol create mode 100644 test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol create mode 100644 test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol create mode 100644 test/libsolidity/semanticTests/extracted/literal_empty_string.sol create mode 100644 test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol create mode 100644 test/libsolidity/semanticTests/extracted/mapping_of_functions.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_overwrite.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_structs_nested.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol create mode 100644 test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol create mode 100644 test/libsolidity/semanticTests/extracted/negative_stack_height.sol create mode 100644 test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol create mode 100644 test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol create mode 100644 test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_functions.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_storage_signed.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol create mode 100644 test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol create mode 100644 test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol create mode 100644 test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol create mode 100644 test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol create mode 100644 test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol create mode 100644 test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol create mode 100644 test/libsolidity/semanticTests/extracted/payable_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol create mode 100644 test/libsolidity/semanticTests/extracted/recursive_structs.sol create mode 100644 test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol create mode 100644 test/libsolidity/semanticTests/extracted/return_in_modifier.sol create mode 100644 test/libsolidity/semanticTests/extracted/revert.sol create mode 100644 test/libsolidity/semanticTests/extracted/ripemd160_empty.sol create mode 100644 test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol create mode 100644 test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol create mode 100644 test/libsolidity/semanticTests/extracted/scientific_notation.sol create mode 100644 test/libsolidity/semanticTests/extracted/send_zero_ether.sol create mode 100644 test/libsolidity/semanticTests/extracted/senders_balance.sol create mode 100644 test/libsolidity/semanticTests/extracted/sha256_empty.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_cleanup.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_constant_left.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_constant_right.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left_uint32.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_left_uint8.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_overflow.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_uint32.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_uint8.sol create mode 100644 test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol create mode 100644 test/libsolidity/semanticTests/extracted/simple_throw.sol create mode 100644 test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol create mode 100644 test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol create mode 100644 test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol create mode 100644 test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol create mode 100644 test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol create mode 100644 test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol create mode 100644 test/libsolidity/semanticTests/extracted/storage_array_ref.sol create mode 100644 test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol create mode 100644 test/libsolidity/semanticTests/extracted/store_bytes.sol create mode 100644 test/libsolidity/semanticTests/extracted/store_function.sol create mode 100644 test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/string_tuples.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_copy.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_delete_member.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_named_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/super.sol create mode 100644 test/libsolidity/semanticTests/extracted/super_alone.sol create mode 100644 test/libsolidity/semanticTests/extracted/super_in_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/super_overload.sol create mode 100644 test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol create mode 100644 test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol create mode 100644 test/libsolidity/semanticTests/extracted/tuples.sol create mode 100644 test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol create mode 100644 test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol create mode 100644 test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol create mode 100644 test/libsolidity/semanticTests/extracted/using_enums.sol create mode 100644 test/libsolidity/semanticTests/extracted/using_inherited_enum.sol create mode 100644 test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol create mode 100644 test/libsolidity/semanticTests/extracted/value_complex.sol create mode 100644 test/libsolidity/semanticTests/extracted/value_for_constructor.sol create mode 100644 test/libsolidity/semanticTests/extracted/value_insane.sol create mode 100644 test/libsolidity/semanticTests/extracted/virtual_function_calls.sol create mode 100644 test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol create mode 100644 test/libsolidity/semanticTests/extracted/write_storage_external.sol diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 2c3dfebace16..ae39bec0ecb4 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -154,7 +154,6 @@ BOOST_AUTO_TEST_CASE(while_loop) ) } - BOOST_AUTO_TEST_CASE(do_while_loop) { char const* sourceCode = R"( @@ -1003,22 +1002,6 @@ BOOST_AUTO_TEST_CASE(constructor) ) } -BOOST_AUTO_TEST_CASE(balance) -{ - char const* sourceCode = R"( - contract test { - constructor() public payable {} - function getBalance() public returns (uint256 balance) { - return address(this).balance; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 23); - ABI_CHECK(callContractFunction("getBalance()"), encodeArgs(23)); - ) -} - BOOST_AUTO_TEST_CASE(blockchain) { char const* sourceCode = R"( @@ -1660,54 +1643,6 @@ BOOST_AUTO_TEST_CASE(fixed_bytes_in_calls) ABI_CHECK(callContractFunction("callHelper(bytes2,bool)", string("\0a", 2), true), encodeArgs(string("\0a\0\0\0", 5))); } -BOOST_AUTO_TEST_CASE(constructor_arguments_internal) -{ - char const* sourceCode = R"( - contract Helper { - bytes3 name; - bool flag; - - constructor(bytes3 x, bool f) public { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - contract Main { - Helper h; - constructor() public { - h = new Helper("abc", true); - } - function getFlag() public returns (bool ret) { return h.getFlag(); } - function getName() public returns (bytes3 ret) { return h.getName(); } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - ABI_CHECK(callContractFunction("getFlag()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("getName()"), encodeArgs("abc")); -} - -BOOST_AUTO_TEST_CASE(constructor_arguments_external) -{ - char const* sourceCode = R"( - contract Main { - bytes3 name; - bool flag; - - constructor(bytes3 x, bool f) public { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - )"; - compileAndRun(sourceCode, 0, "Main", encodeArgs("abc", true)); - ABI_CHECK(callContractFunction("getFlag()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("getName()"), encodeArgs("abc")); -} - BOOST_AUTO_TEST_CASE(constructor_with_long_arguments) { char const* sourceCode = R"( @@ -1736,63 +1671,6 @@ BOOST_AUTO_TEST_CASE(constructor_with_long_arguments) ABI_CHECK(callContractFunction("b()"), encodeDyn(b)); } -BOOST_AUTO_TEST_CASE(constructor_static_array_argument) -{ - char const* sourceCode = R"( - contract C { - uint public a; - uint[3] public b; - - constructor(uint _a, uint[3] memory _b) public { - a = _a; - b = _b; - } - } - )"; - compileAndRun(sourceCode, 0, "C", encodeArgs(u256(1), u256(2), u256(3), u256(4))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("b(uint256)", u256(0)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("b(uint256)", u256(1)), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("b(uint256)", u256(2)), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(constant_var_as_array_length) -{ - char const* sourceCode = R"( - contract C { - uint constant LEN = 3; - uint[LEN] public a; - - constructor(uint[LEN] memory _a) public { - a = _a; - } - } - )"; - compileAndRun(sourceCode, 0, "C", encodeArgs(u256(1), u256(2), u256(3))); - ABI_CHECK(callContractFunction("a(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("a(uint256)", u256(1)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("a(uint256)", u256(2)), encodeArgs(u256(3))); -} - -BOOST_AUTO_TEST_CASE(functions_called_by_constructor) -{ - char const* sourceCode = R"( - contract Test { - bytes3 name; - bool flag; - constructor() public { - setName("abc"); - } - function getName() public returns (bytes3 ret) { return name; } - function setName(bytes3 _name) private { name = _name; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); - ) -} - BOOST_AUTO_TEST_CASE(contracts_as_addresses) { char const* sourceCode = R"( @@ -1813,97 +1691,6 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } -BOOST_AUTO_TEST_CASE(gas_and_value_basic) -{ - char const* sourceCode = R"( - contract helper { - bool flag; - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - function setFlag() public { flag = true; } - function getFlag() public returns (bool fl) { return flag; } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - return h.getBalance.value(amount)(); - } - function outOfGas() public returns (bool ret) { - h.setFlag.gas(2)(); // should fail due to OOG - return true; - } - function checkState() public returns (bool flagAfter, uint myBal) { - flagAfter = h.getFlag(); - myBal = address(this).balance; - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); - // call to helper should not succeed but amount should be transferred anyway - BOOST_REQUIRE(callContractFunction("outOfGas()") == bytes()); - BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5)); -} - -BOOST_AUTO_TEST_CASE(gas_and_value_brace_syntax) -{ - char const* sourceCode = R"( - contract helper { - bool flag; - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - function setFlag() public { flag = true; } - function getFlag() public returns (bool fl) { return flag; } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - return h.getBalance{value: amount}(); - } - function outOfGas() public returns (bool ret) { - h.setFlag{gas: 2}(); // should fail due to OOG - return true; - } - function checkState() public returns (bool flagAfter, uint myBal) { - flagAfter = h.getFlag(); - myBal = address(this).balance; - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); - // call to helper should not succeed but amount should be transferred anyway - BOOST_REQUIRE(callContractFunction("outOfGas()") == bytes()); - BOOST_REQUIRE(callContractFunction("checkState()") == encodeArgs(false, 20 - 5)); -} - -BOOST_AUTO_TEST_CASE(gasleft_decrease) -{ - char const* sourceCode = R"( - contract C { - uint v; - function f() public returns (bool) { - uint startGas = gasleft(); - v++; - assert(startGas > gasleft()); - return true; - } - function g() public returns (bool) { - uint startGas = gasleft(); - assert(startGas > gasleft()); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(gaslimit) { char const* sourceCode = R"( @@ -1966,10029 +1753,4611 @@ BOOST_AUTO_TEST_CASE(blockhash) ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes)); } -BOOST_AUTO_TEST_CASE(value_complex) +BOOST_AUTO_TEST_CASE(internal_constructor) { char const* sourceCode = R"( - contract helper { - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; - } - } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public payable returns (uint256 bal) { - uint someStackElement = 20; - return h.getBalance.value(amount).gas(1000).value(amount + 3)(); - } + contract C { + constructor() internal {} } )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); + BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty()); } -BOOST_AUTO_TEST_CASE(value_insane) +BOOST_AUTO_TEST_CASE(default_fallback_throws) { - char const* sourceCode = R"( - contract helper { - function getBalance() payable public returns (uint256 myBalance) { - return address(this).balance; + char const* sourceCode = R"YY( + contract A { + function f() public returns (bool) { + (bool success,) = address(this).call(""); + return success; } } - contract test { - helper h; - constructor() public payable { h = new helper(); } - function sendAmount(uint amount) public returns (uint256 bal) { - return h.getBalance.value(amount).gas(1000).value(amount + 3)();// overwrite value + )YY"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); + + if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall()) + { + char const* sourceCode = R"YY( + contract A { + function f() public returns (bool) { + (bool success, bytes memory data) = address(this).staticcall(""); + assert(data.length == 0); + return success; + } } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); + )YY"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); + } } -BOOST_AUTO_TEST_CASE(value_for_constructor) +BOOST_AUTO_TEST_CASE(event) { char const* sourceCode = R"( - contract Helper { - bytes3 name; - bool flag; - constructor(bytes3 x, bool f) public payable { - name = x; - flag = f; - } - function getName() public returns (bytes3 ret) { return name; } - function getFlag() public returns (bool ret) { return flag; } - } - contract Main { - Helper h; - constructor() public payable { - h = (new Helper).value(10)("abc", true); + contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id, bool _manually) public payable { + if (_manually) { + bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f; + log3(bytes32(msg.value), s, bytes32(uint256(msg.sender)), _id); + } else { + emit Deposit(msg.sender, _id, msg.value); + } } - function getFlag() public returns (bool ret) { return h.getFlag(); } - function getName() public returns (bytes3 ret) { return h.getName(); } - function getBalances() public returns (uint me, uint them) { me = address(this).balance; them = address(h).balance;} } )"; - compileAndRun(sourceCode, 22, "Main"); - BOOST_REQUIRE(callContractFunction("getFlag()") == encodeArgs(true)); - BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); - BOOST_REQUIRE(callContractFunction("getBalances()") == encodeArgs(12, 10)); + compileAndRun(sourceCode); + u256 value(18); + u256 id(0x1234); + for (bool manually: {true, false}) + { + callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); + BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); + BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); + } } -BOOST_AUTO_TEST_CASE(virtual_function_calls) +BOOST_AUTO_TEST_CASE(event_emit) { char const* sourceCode = R"( - contract Base { - function f() public returns (uint i) { return g(); } - function g() public virtual returns (uint i) { return 1; } - } - contract Derived is Base { - function g() public override returns (uint i) { return 2; } + contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value); + } } )"; ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(2)); + compileAndRun(sourceCode); + u256 value(18); + u256 id(0x1234); + callContractFunctionWithValue("deposit(bytes32)", value, id); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); + BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); + BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); ) } -BOOST_AUTO_TEST_CASE(access_base_storage) +BOOST_AUTO_TEST_CASE(event_no_arguments) { char const* sourceCode = R"( - contract Base { - uint dataBase; - function getViaBase() public returns (uint i) { return dataBase; } - } - contract Derived is Base { - uint dataDerived; - function setData(uint base, uint derived) public returns (bool r) { - dataBase = base; - dataDerived = derived; - return true; - } - function getViaDerived() public returns (uint base, uint derived) { - base = dataBase; - derived = dataDerived; + contract ClientReceipt { + event Deposit(); + function deposit() public { + emit Deposit(); } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("setData(uint256,uint256)", 1, 2), encodeArgs(true)); - ABI_CHECK(callContractFunction("getViaBase()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("getViaDerived()"), encodeArgs(1, 2)); - ) -} -BOOST_AUTO_TEST_CASE(single_copy_with_multiple_inheritance) -{ - char const* sourceCode = R"( - contract Base { - uint data; - function setData(uint i) public { data = i; } - function getViaBase() public returns (uint i) { return data; } - } - contract A is Base { function setViaA(uint i) public { setData(i); } } - contract B is Base { function getViaB() public returns (uint i) { return getViaBase(); } } - contract Derived is Base, B, A { } - )"; ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getViaB()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("setViaA(uint256)", 23), encodeArgs()); - ABI_CHECK(callContractFunction("getViaB()"), encodeArgs(23)); + compileAndRun(sourceCode); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0).empty()); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); ) } -BOOST_AUTO_TEST_CASE(explicit_base_class) +BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit) { char const* sourceCode = R"( - contract BaseBase { function g() public virtual returns (uint r) { return 1; } } - contract Base is BaseBase { function g() public virtual override returns (uint r) { return 2; } } - contract Derived is Base { - function f() public returns (uint r) { return BaseBase.g(); } - function g() public override returns (uint r) { return 3; } + contract A { + event x(); + } + contract B is A { + function f() public returns (uint) { + emit A.x(); + return 1; + } } )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); + compileAndRun(sourceCode); + callContractFunction("f()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0).empty()); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()"))); } -BOOST_AUTO_TEST_CASE(base_constructor_arguments) +BOOST_AUTO_TEST_CASE(events_with_same_name) { char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - } - contract Base is BaseBase(7) { - constructor() public { - m_a *= m_a; + contract ClientReceipt { + event Deposit(); + event Deposit(address _addr); + event Deposit(address _addr, uint _amount); + event Deposit(address _addr, bool _flag); + function deposit() public returns (uint) { + emit Deposit(); + return 1; + } + function deposit(address _addr) public returns (uint) { + emit Deposit(_addr); + return 2; + } + function deposit(address _addr, uint _amount) public returns (uint) { + emit Deposit(_addr, _amount); + return 3; + } + function deposit(address _addr, bool _flag) public returns (uint) { + emit Deposit(_addr, _flag); + return 4; } - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } } )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(7 * 7)); + u160 const c_loggedAddress = m_contractAddress; + + ALSO_VIA_YUL( + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0).empty()); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); + + ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + ABI_CHECK(logData(0), encodeArgs(c_loggedAddress)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); + + ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); + + ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, false)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bool)"))); + ) } -BOOST_AUTO_TEST_CASE(function_usage_in_constructor_arguments) +BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit) { char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - function g() public returns (uint r) { return 2; } + contract A { + event Deposit(); } - contract Base is BaseBase(BaseBase.g()) { + + contract B { + event Deposit(address _addr); } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } + + contract ClientReceipt is A, B { + event Deposit(address _addr, uint _amount); + function deposit() public returns (uint) { + emit Deposit(); + return 1; + } + function deposit(address _addr) public returns (uint) { + emit Deposit(_addr); + return 1; + } + function deposit(address _addr, uint _amount) public returns (uint) { + emit Deposit(_addr, _amount); + return 1; + } } )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(2)); + u160 const c_loggedAddress = m_contractAddress; + + ALSO_VIA_YUL( + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0).empty()); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); + + ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(c_loggedAddress)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); + + ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); + ) } -BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments) +BOOST_AUTO_TEST_CASE(event_anonymous) { char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; + contract ClientReceipt { + event Deposit() anonymous; + function deposit() public { + emit Deposit(); } - function overridden() public virtual returns (uint r) { return 1; } - function g() public returns (uint r) { return overridden(); } - } - contract Base is BaseBase(BaseBase.g()) { - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } - function overridden() public override returns (uint r) { return 2; } } )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(2)); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 0); + ) } -BOOST_AUTO_TEST_CASE(internal_constructor) +BOOST_AUTO_TEST_CASE(event_anonymous_with_topics) { char const* sourceCode = R"( - contract C { - constructor() internal {} + contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous; + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value, 2, "abc"); + } } )"; - BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty()); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + u256 value(18); + u256 id(0x1234); + callContractFunctionWithValue("deposit(bytes32)", value, id); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs("abc")); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 4); + BOOST_CHECK_EQUAL(logTopic(0, 0), h256(m_sender, h256::AlignRight)); + BOOST_CHECK_EQUAL(logTopic(0, 1), h256(id)); + BOOST_CHECK_EQUAL(logTopic(0, 2), h256(value)); + BOOST_CHECK_EQUAL(logTopic(0, 3), h256(2)); + ) } -BOOST_AUTO_TEST_CASE(function_modifier) +BOOST_AUTO_TEST_CASE(event_lots_of_data) { char const* sourceCode = R"( - contract C { - function getOne() payable nonFree public returns (uint r) { return 1; } - modifier nonFree { if (msg.value > 0) _; } + contract ClientReceipt { + event Deposit(address _from, bytes32 _id, uint _value, bool _flag); + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value, true); + } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getOne()"), encodeArgs(0)); - ABI_CHECK(callContractFunctionWithValue("getOne()", 1), encodeArgs(1)); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + u256 value(18); + u256 id(0x1234); + callContractFunctionWithValue("deposit(bytes32)", value, id); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs((u160)m_sender, id, value, true)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256,bool)"))); + ) } -BOOST_AUTO_TEST_CASE(function_modifier_local_variables) +BOOST_AUTO_TEST_CASE(event_really_lots_of_data) { char const* sourceCode = R"( - contract C { - modifier mod1 { uint8 a = 1; uint8 b = 2; _; } - modifier mod2(bool a) { if (a) return; else _; } - function f(bool a) mod1 mod2(a) public returns (uint r) { return 3; } + contract ClientReceipt { + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + emit Deposit(10, msg.data, 15); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(0)); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(3)); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(util::keccak256("deposit()")).asBytes())))); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); } -BOOST_AUTO_TEST_CASE(function_modifier_loop) +BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) { char const* sourceCode = R"( - contract C { - modifier repeat(uint count) { uint i; for (i = 0; i < count; ++i) _; } - function f() repeat(10) public returns (uint r) { r += 1; } + contract ClientReceipt { + bytes x; + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + x.push("A"); + x.push("B"); + x.push("C"); + emit Deposit(10, x, 15); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(10)); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC")))); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); } -BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation) +BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) { char const* sourceCode = R"( - contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; } + contract ClientReceipt { + bytes x; + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + x = new bytes(31); + x[0] = "A"; + x[1] = "B"; + x[2] = "C"; + x[30] = "Z"; + emit Deposit(10, x, 15); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z")); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); } -BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return) +BOOST_AUTO_TEST_CASE(event_struct_memory_v2) { - // Note that return sets the return variable and jumps to the end of the current function or - // modifier code block. char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; return r; } + struct S { uint a; } + event E(S); + function createEvent(uint x) public { + emit E(S(x)); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(x)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); } -BOOST_AUTO_TEST_CASE(function_modifier_overriding) +BOOST_AUTO_TEST_CASE(event_struct_storage_v2) { char const* sourceCode = R"( - contract A { - function f() mod public returns (bool r) { return true; } - modifier mod virtual { _; } - } - contract C is A { - modifier mod override { if (false) _; } + pragma experimental ABIEncoderV2; + contract C { + struct S { uint a; } + event E(S); + S s; + function createEvent(uint x) public { + s.a = x; + emit E(s); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(false)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(x)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); } -BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context) +BOOST_AUTO_TEST_CASE(event_dynamic_array_memory) { char const* sourceCode = R"( - contract A { - uint data; - constructor() mod1 public { f1(); } - function f1() mod2 public { data |= 0x1; } - function f2() public { data |= 0x20; } - function f3() public virtual { } - modifier mod1 virtual { f2(); _; } - modifier mod2 { f3(); if (false) _; } - function getData() public returns (uint r) { return data; } - } - contract C is A { - modifier mod1 override { f4(); _; } - function f3() public override { data |= 0x300; } - function f4() public { data |= 0x4000; } + contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(0x4300)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); } -BOOST_AUTO_TEST_CASE(function_modifier_for_constructor) +BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2) { char const* sourceCode = R"( - contract A { - uint data; - constructor() mod1 public { data |= 2; } - modifier mod1 virtual { data |= 1; _; } - function getData() public returns (uint r) { return data; } - } - contract C is A { - modifier mod1 override { data |= 4; _; } + pragma experimental ABIEncoderV2; + contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(4 | 2)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); } -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times) +BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - uint public a; - modifier mod(uint x) { a += x; _; } - function f(uint x) mod(2) mod(5) mod(x) public returns(uint) { return a; } + event E(uint[][]); + function createEvent(uint x) public { + uint[][] memory arr = new uint[][](2); + arr[0] = new uint[](2); + arr[1] = new uint[](2); + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); + } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(2 + 5 + 3)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); } -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars) +BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) { char const* sourceCode = R"( contract C { - uint public a; - modifier mod(uint x) { uint b = x; a += b; _; a -= b; assert(b == x); } - function f(uint x) mod(2) mod(5) mod(x) public returns(uint) { return a; } + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + while (arr.length < 3) + arr.push(); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(0)); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); + ) } -BOOST_AUTO_TEST_CASE(function_modifier_library) +BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2) { char const* sourceCode = R"( - library L { - struct S { uint v; } - modifier mod(S storage s) { s.v++; _; } - function libFun(S storage s) mod(s) internal { s.v += 0x100; } + pragma experimental ABIEncoderV2; + contract C { + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + while (arr.length < 3) + arr.push(); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } } + )"; + ALSO_VIA_YUL( + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); + ) +} - contract Test { - using L for *; - L.S s; - - function f() public returns (uint) { - s.libFun(); - L.libFun(s); - return s.v; +BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + event E(uint[][]); + uint[][] arr; + function createEvent(uint x) public { + arr.push(new uint[](2)); + arr.push(new uint[](2)); + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); } } )"; + /// TODO enable again after push(..) via yul is implemented for nested arrays. + /// ALSO_VIA_YUL() compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); } -BOOST_AUTO_TEST_CASE(function_modifier_library_inheritance) +BOOST_AUTO_TEST_CASE(event_indexed_string) { - // Tests that virtual lookup for modifiers in libraries does not consider - // the current inheritance hierarchy. - char const* sourceCode = R"( - library L { - struct S { uint v; } - modifier mod(S storage s) { s.v++; _; } - function libFun(S storage s) mod(s) internal { s.v += 0x100; } - } - - contract Test { - using L for *; - L.S s; - modifier mod(L.S storage) { revert(); _; } - - function f() public returns (uint) { - s.libFun(); - L.libFun(s); - return s.v; + contract C { + string x; + uint[4] y; + event E(string indexed r, uint[4] indexed t); + function deposit() public { + for (uint i = 0; i < 90; i++) + bytes(x).push(0); + for (uint8 i = 0; i < 90; i++) + bytes(x)[i] = byte(i); + y[0] = 4; + y[1] = 5; + y[2] = 6; + y[3] = 7; + emit E(x, y); } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); + callContractFunction("deposit()"); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + string dynx(90, 0); + for (size_t i = 0; i < dynx.size(); ++i) + dynx[i] = i; + BOOST_CHECK(logData(0) == bytes()); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); + BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(dynx)); + BOOST_CHECK_EQUAL(logTopic(0, 2), util::keccak256( + encodeArgs(u256(4), u256(5), u256(6), u256(7)) + )); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string,uint256[4])"))); } -BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack) +BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) { char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - uint; uint; uint; uint; - int x = -7; - return uint(x); + contract test { + function f(uint, uint k) public returns(uint ret_k, uint ret_g){ + uint g = 8; + ret_k = k; + ret_g = g; } } )"; ALSO_VIA_YUL( compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(-7))); + BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8)); + ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8)); ) } -BOOST_AUTO_TEST_CASE(super) +BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) { char const* sourceCode = R"( - contract A { function f() public virtual returns (uint r) { return 1; } } - contract B is A { function f() public virtual override returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public virtual override returns (uint r) { return super.f() | 4; } } - contract D is B, C { function f() public override(B, C) returns (uint r) { return super.f() | 8; } } + contract c { + function foo(uint a, uint b, uint c) public returns (bytes32 d) + { + d = keccak256(abi.encodePacked(a, b, c)); + } + } )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); -} + compileAndRun(sourceCode); -BOOST_AUTO_TEST_CASE(super_in_constructor) -{ - char const* sourceCode = R"( - contract A { function f() public virtual returns (uint r) { return 1; } } - contract B is A { function f() public virtual override returns (uint r) { return super.f() | 2; } } - contract C is A { function f() public virtual override returns (uint r) { return super.f() | 4; } } - contract D is B, C { uint data; constructor() public { data = super.f() | 8; } function f() public override (B, C) returns (uint r) { return data; } } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); + ABI_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13), encodeArgs( + util::keccak256( + toBigEndian(u256(10)) + + toBigEndian(u256(12)) + + toBigEndian(u256(13)) + ) + )); } -BOOST_AUTO_TEST_CASE(super_alone) +BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_numeric_literals) { char const* sourceCode = R"( - contract A { function f() public { super; } } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "A"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(default_fallback_throws) -{ - char const* sourceCode = R"YY( - contract A { - function f() public returns (bool) { - (bool success,) = address(this).call(""); - return success; + contract c { + function foo(uint a, uint16 b) public returns (bytes32 d) + { + d = keccak256(abi.encodePacked(a, b, uint8(145))); } } - )YY"; + )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); - if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall()) - { - char const* sourceCode = R"YY( - contract A { - function f() public returns (bool) { - (bool success, bytes memory data) = address(this).staticcall(""); - assert(data.length == 0); - return success; - } - } - )YY"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); - } + ABI_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12), encodeArgs( + util::keccak256( + toBigEndian(u256(10)) + + bytes{0x0, 0xc} + + bytes(1, 0x91) + ) + )); } -BOOST_AUTO_TEST_CASE(event) +BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals) { char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint _value); - function deposit(bytes32 _id, bool _manually) public payable { - if (_manually) { - bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f; - log3(bytes32(msg.value), s, bytes32(uint256(msg.sender)), _id); - } else { - emit Deposit(msg.sender, _id, msg.value); - } + contract c { + function foo() public returns (bytes32 d) + { + d = keccak256("foo"); + } + function bar(uint a, uint16 b) public returns (bytes32 d) + { + d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); } } )"; compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - for (bool manually: {true, false}) - { - callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); - } -} - -BOOST_AUTO_TEST_CASE(event_emit) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint _value); - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); - ) -} - -BOOST_AUTO_TEST_CASE(event_no_arguments) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(); - function deposit() public { - emit Deposit(); - } - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit) -{ - char const* sourceCode = R"( - contract A { - event x(); - } - contract B is A { - function f() public returns (uint) { - emit A.x(); - return 1; - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("f()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()"))); -} - -BOOST_AUTO_TEST_CASE(events_with_same_name) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(); - event Deposit(address _addr); - event Deposit(address _addr, uint _amount); - event Deposit(address _addr, bool _flag); - function deposit() public returns (uint) { - emit Deposit(); - return 1; - } - function deposit(address _addr) public returns (uint) { - emit Deposit(_addr); - return 2; - } - function deposit(address _addr, uint _amount) public returns (uint) { - emit Deposit(_addr, _amount); - return 3; - } - function deposit(address _addr, bool _flag) public returns (uint) { - emit Deposit(_addr, _flag); - return 4; - } - } - )"; - u160 const c_loggedAddress = m_contractAddress; - - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - - ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); - - ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); - - ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, false)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bool)"))); - ) -} - -BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit) -{ - char const* sourceCode = R"( - contract A { - event Deposit(); - } - - contract B { - event Deposit(address _addr); - } - - contract ClientReceipt is A, B { - event Deposit(address _addr, uint _amount); - function deposit() public returns (uint) { - emit Deposit(); - return 1; - } - function deposit(address _addr) public returns (uint) { - emit Deposit(_addr); - return 1; - } - function deposit(address _addr, uint _amount) public returns (uint) { - emit Deposit(_addr, _amount); - return 1; - } - } - )"; - u160 const c_loggedAddress = m_contractAddress; - - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - - ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(c_loggedAddress)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); - - ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_anonymous) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit() anonymous; - function deposit() public { - emit Deposit(); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 0); - ) -} - -BOOST_AUTO_TEST_CASE(event_anonymous_with_topics) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous; - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value, 2, "abc"); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs("abc")); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 4); - BOOST_CHECK_EQUAL(logTopic(0, 0), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(id)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(value)); - BOOST_CHECK_EQUAL(logTopic(0, 3), h256(2)); - ) -} - -BOOST_AUTO_TEST_CASE(event_lots_of_data) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address _from, bytes32 _id, uint _value, bool _flag); - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value, true); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs((u160)m_sender, id, value, true)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256,bool)"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_really_lots_of_data) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - emit Deposit(10, msg.data, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(util::keccak256("deposit()")).asBytes())))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) -{ - char const* sourceCode = R"( - contract ClientReceipt { - bytes x; - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - x.push("A"); - x.push("B"); - x.push("C"); - emit Deposit(10, x, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC")))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) -{ - char const* sourceCode = R"( - contract ClientReceipt { - bytes x; - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - x = new bytes(31); - x[0] = "A"; - x[1] = "B"; - x[2] = "C"; - x[30] = "Z"; - emit Deposit(10, x, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z")); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_struct_memory_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; } - event E(S); - function createEvent(uint x) public { - emit E(S(x)); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(x)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); -} - -BOOST_AUTO_TEST_CASE(event_struct_storage_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; } - event E(S); - S s; - function createEvent(uint x) public { - s.a = x; - emit E(s); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(x)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_memory) -{ - char const* sourceCode = R"( - contract C { - event E(uint[]); - function createEvent(uint x) public { - uint[] memory arr = new uint[](3); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - event E(uint[]); - function createEvent(uint x) public { - uint[] memory arr = new uint[](3); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - event E(uint[][]); - function createEvent(uint x) public { - uint[][] memory arr = new uint[][](2); - arr[0] = new uint[](2); - arr[1] = new uint[](2); - arr[0][0] = x; - arr[0][1] = x + 1; - arr[1][0] = x + 2; - arr[1][1] = x + 3; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) -{ - char const* sourceCode = R"( - contract C { - event E(uint[]); - uint[] arr; - function createEvent(uint x) public { - while (arr.length < 3) - arr.push(); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - event E(uint[]); - uint[] arr; - function createEvent(uint x) public { - while (arr.length < 3) - arr.push(); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - event E(uint[][]); - uint[][] arr; - function createEvent(uint x) public { - arr.push(new uint[](2)); - arr.push(new uint[](2)); - arr[0][0] = x; - arr[0][1] = x + 1; - arr[1][0] = x + 2; - arr[1][1] = x + 3; - emit E(arr); - } - } - )"; - /// TODO enable again after push(..) via yul is implemented for nested arrays. - /// ALSO_VIA_YUL() - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); -} - -BOOST_AUTO_TEST_CASE(event_indexed_string) -{ - char const* sourceCode = R"( - contract C { - string x; - uint[4] y; - event E(string indexed r, uint[4] indexed t); - function deposit() public { - for (uint i = 0; i < 90; i++) - bytes(x).push(0); - for (uint8 i = 0; i < 90; i++) - bytes(x)[i] = byte(i); - y[0] = 4; - y[1] = 5; - y[2] = 6; - y[3] = 7; - emit E(x, y); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - string dynx(90, 0); - for (size_t i = 0; i < dynx.size(); ++i) - dynx[i] = i; - BOOST_CHECK(logData(0) == bytes()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(dynx)); - BOOST_CHECK_EQUAL(logTopic(0, 2), util::keccak256( - encodeArgs(u256(4), u256(5), u256(6), u256(7)) - )); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string,uint256[4])"))); -} - -BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) -{ - char const* sourceCode = R"( - contract test { - function f(uint, uint k) public returns(uint ret_k, uint ret_g){ - uint g = 8; - ret_k = k; - ret_g = g; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8)); - ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8)); - ) -} - -BOOST_AUTO_TEST_CASE(empty_name_return_parameter) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) public returns(uint){ - return k; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", 9), encodeArgs(9)); - ) -} - -BOOST_AUTO_TEST_CASE(sha256_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes32) { - return sha256(""); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); -} - -BOOST_AUTO_TEST_CASE(ripemd160_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes20) { - return ripemd160(""); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000")); -} - -BOOST_AUTO_TEST_CASE(keccak256_empty) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes32) { - return keccak256(""); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); - ) -} - -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) -{ - char const* sourceCode = R"( - contract c { - function foo(uint a, uint b, uint c) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, c)); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - toBigEndian(u256(12)) + - toBigEndian(u256(13)) - ) - )); -} - -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_numeric_literals) -{ - char const* sourceCode = R"( - contract c { - function foo(uint a, uint16 b) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, uint8(145))); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - bytes{0x0, 0xc} + - bytes(1, 0x91) - ) - )); -} - -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals) -{ - char const* sourceCode = R"( - contract c { - function foo() public returns (bytes32 d) - { - d = keccak256("foo"); - } - function bar(uint a, uint16 b) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo()"), encodeArgs(util::keccak256("foo"))); - - ABI_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - bytes{0x0, 0xc} + - bytes(1, 0x91) + - bytes{0x66, 0x6f, 0x6f} - ) - )); -} - -BOOST_AUTO_TEST_CASE(keccak256_with_bytes) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function foo() public returns (bool) - { - data.push("f"); - data.push("o"); - data.push("o"); - return keccak256(data) == keccak256("foo"); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(iterated_keccak256_with_bytes) -{ - char const* sourceCode = R"ABC( - contract c { - bytes data; - function foo() public returns (bytes32) - { - data.push("x"); - data.push("y"); - data.push("z"); - return keccak256(abi.encodePacked("b", keccak256(data), "a")); - } - } - )ABC"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo()"), encodeArgs( - u256(util::keccak256(bytes{'b'} + util::keccak256("xyz").asBytes() + bytes{'a'})) - )); -} - -BOOST_AUTO_TEST_CASE(generic_call) -{ - char const* sourceCode = R"**( - contract receiver { - uint public received; - function recv(uint256 x) public payable { received = x; } - } - contract sender { - constructor() public payable {} - function doSend(address rec) public returns (uint d) - { - bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)"))); - rec.call.value(2)(abi.encodeWithSelector(signature, 23)); - return receiver(rec).received(); - } - } - )**"; - compileAndRun(sourceCode, 0, "receiver"); - u160 const c_receiverAddress = m_contractAddress; - compileAndRun(sourceCode, 50, "sender"); - BOOST_REQUIRE(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(23)); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 50 - 2); -} - -BOOST_AUTO_TEST_CASE(generic_delegatecall) -{ - char const* sourceCode = R"**( - contract Receiver { - uint public received; - address public sender; - uint public value; - constructor() public payable {} - function recv(uint256 x) public payable { received = x; sender = msg.sender; value = msg.value; } - } - contract Sender { - uint public received; - address public sender; - uint public value; - constructor() public payable {} - function doSend(address rec) public payable - { - bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)"))); - (bool success,) = rec.delegatecall(abi.encodeWithSelector(signature, 23)); - success; - } - } - )**"; - - for (auto v2: {false, true}) - { - string source = (v2 ? "pragma experimental ABIEncoderV2;\n" : "") + string(sourceCode); - - compileAndRun(source, 0, "Receiver"); - u160 const c_receiverAddress = m_contractAddress; - compileAndRun(source, 50, "Sender"); - u160 const c_senderAddress = m_contractAddress; - BOOST_CHECK(m_sender != c_senderAddress); // just for sanity - ABI_CHECK(callContractFunctionWithValue("doSend(address)", 11, c_receiverAddress), encodeArgs()); - ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(23))); - ABI_CHECK(callContractFunction("sender()"), encodeArgs(u160(m_sender))); - ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(11))); - m_contractAddress = c_receiverAddress; - ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("sender()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(0))); - BOOST_CHECK(storageEmpty(c_receiverAddress)); - BOOST_CHECK(!storageEmpty(c_senderAddress)); - BOOST_CHECK_EQUAL(balanceAt(c_receiverAddress), 0); - BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50 + 11); - } -} - -BOOST_AUTO_TEST_CASE(generic_staticcall) -{ - if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall()) - { - char const* sourceCode = R"**( - contract A { - uint public x; - constructor() public { x = 42; } - function pureFunction(uint256 p) public pure returns (uint256) { return p; } - function viewFunction(uint256 p) public view returns (uint256) { return p + x; } - function nonpayableFunction(uint256 p) public returns (uint256) { x = p; return x; } - function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; } - } - contract C { - function f(address a) public view returns (bool, bytes memory) - { - return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23)); - } - function g(address a) public view returns (bool, bytes memory) - { - return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23)); - } - function h(address a) public view returns (bool, bytes memory) - { - return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23)); - } - function i(address a, uint256 v) public view returns (bool, bytes memory) - { - return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v)); - } - } - )**"; - compileAndRun(sourceCode, 0, "A"); - u160 const c_addressA = m_contractAddress; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23)); - ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42)); - ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00)); - ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42)); - ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x00)); - } -} - -BOOST_AUTO_TEST_CASE(library_call_in_homestead) -{ - char const* sourceCode = R"( - library Lib { function m() public returns (address) { return msg.sender; } } - contract Test { - address public sender; - function f() public { - sender = Lib.m(); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("sender()"), encodeArgs(u160(m_sender))); -} - -BOOST_AUTO_TEST_CASE(library_call_protection) -{ - // This tests code that reverts a call if it is a direct call to a library - // as opposed to a delegatecall. - char const* sourceCode = R"( - library Lib { - struct S { uint x; } - // a direct call to this should revert - function np(S storage s) public returns (address) { s.x = 3; return msg.sender; } - // a direct call to this is fine - function v(S storage) public view returns (address) { return msg.sender; } - // a direct call to this is fine - function pu() public pure returns (uint) { return 2; } - } - contract Test { - Lib.S public s; - function np() public returns (address) { return Lib.np(s); } - function v() public view returns (address) { return Lib.v(s); } - function pu() public pure returns (uint) { return Lib.pu(); } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - ABI_CHECK(callContractFunction("np(Lib.S storage)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("v(Lib.S storage)", 0), encodeArgs(u160(m_sender))); - ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("s()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("np()"), encodeArgs(u160(m_sender))); - ABI_CHECK(callContractFunction("s()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("v()"), encodeArgs(u160(m_sender))); - ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); -} - - -BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) -{ - char const* sourceCode = R"( - library Lib { - function x() public view returns (uint) { - return 1; - } - } - contract Test { - uint t; - function f() public returns (uint) { - t = 2; - return this.g(); - } - function g() public view returns (uint) { - return Lib.x(); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(store_bytes) -{ - // this test just checks that the copy loop does not mess up the stack - char const* sourceCode = R"( - contract C { - function save() public returns (uint r) { - r = 23; - savedData = msg.data; - r = 24; - } - bytes savedData; - } - )"; - compileAndRun(sourceCode); - // empty copy loop - ABI_CHECK(callContractFunction("save()"), encodeArgs(24)); - ABI_CHECK(callContractFunction("save()", "abcdefg"), encodeArgs(24)); -} - -BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes32) { - return keccak256(abi.encodePacked("abc", msg.data)); - } - } - )"; - compileAndRun(sourceCode); - bytes calldata1 = FixedHash<4>(util::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); - sendMessage(calldata1, false); - BOOST_CHECK(m_transactionSuccessful); - BOOST_CHECK(m_output == encodeArgs(util::keccak256(bytes{'a', 'b', 'c'} + calldata1))); -} - -BOOST_AUTO_TEST_CASE(call_forward_bytes) -{ - char const* sourceCode = R"( - contract receiver { - uint public received; - function recv(uint x) public { received += x + 1; } - fallback() external { received = 0x80; } - } - contract sender { - constructor() public { rec = new receiver(); } - fallback() external { savedData = msg.data; } - function forward() public returns (bool) { address(rec).call(savedData); return true; } - function clear() public returns (bool) { delete savedData; return true; } - function val() public returns (uint) { return rec.received(); } - receiver rec; - bytes savedData; - } - )"; - compileAndRun(sourceCode, 0, "sender"); - ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes()); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("clear()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80)); -} - -BOOST_AUTO_TEST_CASE(call_forward_bytes_length) -{ - char const* sourceCode = R"( - contract receiver { - uint public calledLength; - fallback() external { calledLength = msg.data.length; } - } - contract sender { - receiver rec; - constructor() public { rec = new receiver(); } - function viaCalldata() public returns (uint) { - (bool success,) = address(rec).call(msg.data); - require(success); - return rec.calledLength(); - } - function viaMemory() public returns (uint) { - bytes memory x = msg.data; - (bool success,) = address(rec).call(x); - require(success); - return rec.calledLength(); - } - bytes s; - function viaStorage() public returns (uint) { - s = msg.data; - (bool success,) = address(rec).call(s); - require(success); - return rec.calledLength(); - } - } - )"; - compileAndRun(sourceCode, 0, "sender"); - - // No additional data, just function selector - ABI_CHECK(callContractFunction("viaCalldata()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("viaMemory()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("viaStorage()"), encodeArgs(4)); - - // Some additional unpadded data - bytes unpadded = asBytes(string("abc")); - ABI_CHECK(callContractFunctionNoEncoding("viaCalldata()", unpadded), encodeArgs(7)); - ABI_CHECK(callContractFunctionNoEncoding("viaMemory()", unpadded), encodeArgs(7)); - ABI_CHECK(callContractFunctionNoEncoding("viaStorage()", unpadded), encodeArgs(7)); -} - -BOOST_AUTO_TEST_CASE(copying_bytes_multiassign) -{ - char const* sourceCode = R"( - contract receiver { - uint public received; - function recv(uint x) public { received += x + 1; } - fallback() external { received = 0x80; } - } - contract sender { - constructor() public { rec = new receiver(); } - fallback() external { savedData1 = savedData2 = msg.data; } - function forward(bool selector) public returns (bool) { - if (selector) { address(rec).call(savedData1); delete savedData1; } - else { address(rec).call(savedData2); delete savedData2; } - return true; - } - function val() public returns (uint) { return rec.received(); } - receiver rec; - bytes savedData1; - bytes savedData2; - } - )"; - compileAndRun(sourceCode, 0, "sender"); - ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes()); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("forward(bool)", false), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(16)); - ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true)); - ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80)); -} - -BOOST_AUTO_TEST_CASE(delete_removes_bytes_data) -{ - char const* sourceCode = R"( - contract c { - fallback() external { data = msg.data; } - function del() public returns (bool) { delete data; return true; } - bytes data; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("---", 7), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) -{ - char const* sourceCode = R"( - contract c { - function set() public returns (bool) { data = msg.data; return true; } - fallback() external { data = msg.data; } - bytes data; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - sendMessage(bytes(), false); - BOOST_CHECK(m_transactionSuccessful); - BOOST_CHECK(m_output.empty()); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(copy_removes_bytes_data) -{ - char const* sourceCode = R"( - contract c { - function set() public returns (bool) { data1 = msg.data; return true; } - function reset() public returns (bool) { data1 = data2; return true; } - bytes data1; - bytes data2; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("reset()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(bytes_inside_mappings) -{ - char const* sourceCode = R"( - contract c { - function set(uint key) public returns (bool) { data[key] = msg.data; return true; } - function copy(uint from, uint to) public returns (bool) { data[to] = data[from]; return true; } - mapping(uint => bytes) data; - } - )"; - compileAndRun(sourceCode); - // store a short byte array at 1 and a longer one at 2 - ABI_CHECK(callContractFunction("set(uint256)", 1, 2), encodeArgs(true)); - ABI_CHECK(callContractFunction("set(uint256)", 2, 2, 3, 4, 5), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - // copy shorter to longer - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 1, 2), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - // copy empty to both - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 1), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 2), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(bytes_length_member) -{ - char const* sourceCode = R"( - contract c { - function set() public returns (bool) { data = msg.data; return true; } - function getLength() public returns (uint) { return data.length; } - bytes data; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getLength()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("set()", 1, 2), encodeArgs(true)); - ABI_CHECK(callContractFunction("getLength()"), encodeArgs(4+32+32)); -} - -BOOST_AUTO_TEST_CASE(struct_copy) -{ - char const* sourceCode = R"( - contract c { - struct Nested { uint x; uint y; } - struct Struct { uint a; mapping(uint => Struct) b; Nested nested; uint c; } - mapping(uint => Struct) data; - function set(uint k) public returns (bool) { - data[k].a = 1; - data[k].nested.x = 3; - data[k].nested.y = 4; - data[k].c = 2; - return true; - } - function copy(uint from, uint to) public returns (bool) { - data[to] = data[from]; - return true; - } - function retrieve(uint k) public returns (uint a, uint x, uint y, uint c) - { - a = data[k].a; - x = data[k].nested.x; - y = data[k].nested.y; - c = data[k].c; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set(uint256)", 7), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 7, 8), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 0, 7), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 7), encodeArgs(0, 0, 0, 0)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(1, 3, 4, 2)); - ABI_CHECK(callContractFunction("copy(uint256,uint256)", 7, 8), encodeArgs(true)); - ABI_CHECK(callContractFunction("retrieve(uint256)", 8), encodeArgs(0, 0, 0, 0)); -} - -BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) -{ - char const* sourceCode = R"( - contract c { - struct Struct { uint a; bytes data; uint b; } - Struct data1; - Struct data2; - function set(uint _a, bytes calldata _data, uint _b) external returns (bool) { - data1.a = _a; - data1.b = _b; - data1.data = _data; - return true; - } - function copy() public returns (bool) { - data1 = data2; - return true; - } - function del() public returns (bool) { - delete data1; - return true; - } - } - )"; - compileAndRun(sourceCode); - string data = "123456789012345678901234567890123"; - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("copy()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("del()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(struct_copy_via_local) -{ - char const* sourceCode = R"( - contract c { - struct Struct { uint a; uint b; } - Struct data1; - Struct data2; - function test() public returns (bool) { - data1.a = 1; - data1.b = 2; - Struct memory x = data1; - data2 = x; - return data2.a == data1.a && data2.b == data1.b; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(using_enums) -{ - char const* sourceCode = R"( - contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } - constructor() public - { - choices = ActionChoices.GoStraight; - } - function getChoice() public returns (uint d) - { - d = uint256(choices); - } - ActionChoices choices; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getChoice()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(enum_explicit_overflow) -{ - char const* sourceCode = R"( - contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight } - constructor() public - { - } - function getChoiceExp(uint x) public returns (uint d) - { - choice = ActionChoices(x); - d = uint256(choice); - } - function getChoiceFromSigned(int x) public returns (uint d) - { - choice = ActionChoices(x); - d = uint256(choice); - } - function getChoiceFromNegativeLiteral() public returns (uint d) - { - choice = ActionChoices(-1); - d = uint256(choice); - } - ActionChoices choice; - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - // These should throw - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 3), encodeArgs()); - ABI_CHECK(callContractFunction("getChoiceFromSigned(int256)", -1), encodeArgs()); - ABI_CHECK(callContractFunction("getChoiceFromNegativeLiteral()"), encodeArgs()); - // These should work - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 2), encodeArgs(2)); - ABI_CHECK(callContractFunction("getChoiceExp(uint256)", 0), encodeArgs(0)); - ) -} - -BOOST_AUTO_TEST_CASE(storing_invalid_boolean) -{ - char const* sourceCode = R"( - contract C { - event Ev(bool); - bool public perm; - function set() public returns(uint) { - bool tmp; - assembly { - tmp := 5 - } - perm = tmp; - return 1; - } - function ret() public returns(bool) { - bool tmp; - assembly { - tmp := 5 - } - return tmp; - } - function ev() public returns(uint) { - bool tmp; - assembly { - tmp := 5 - } - emit Ev(tmp); - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("perm()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("ret()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("ev()"), encodeArgs(1)); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(1)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Ev(bool)"))); -} - - -BOOST_AUTO_TEST_CASE(using_contract_enums_with_explicit_contract_name) -{ - char const* sourceCode = R"( - contract test { - enum Choice { A, B, C } - function answer () public returns (test.Choice _ret) - { - _ret = test.Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(using_inherited_enum) -{ - char const* sourceCode = R"( - contract base { - enum Choice { A, B, C } - } - - contract test is base { - function answer () public returns (Choice _ret) - { - _ret = Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(using_inherited_enum_excplicitly) -{ - char const* sourceCode = R"( - contract base { - enum Choice { A, B, C } - } - - contract test is base { - function answer () public returns (base.Choice _ret) - { - _ret = base.Choice.B; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("answer()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) -{ - char const* sourceCode = R"( - contract c { - enum Truth { False, True } - function test() public returns (uint) - { - return uint(Truth(uint8(0x701))); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); - ) -} - -BOOST_AUTO_TEST_CASE(struct_referencing) -{ - static char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - interface I { - struct S { uint a; } - } - library L { - struct S { uint b; uint a; } - function f() public pure returns (S memory) { - S memory s; - s.a = 3; - return s; - } - function g() public pure returns (I.S memory) { - I.S memory s; - s.a = 4; - return s; - } - // argument-dependant lookup tests - function a(I.S memory) public pure returns (uint) { return 1; } - function a(S memory) public pure returns (uint) { return 2; } - } - contract C is I { - function f() public pure returns (S memory) { - S memory s; - s.a = 1; - return s; - } - function g() public pure returns (I.S memory) { - I.S memory s; - s.a = 2; - return s; - } - function h() public pure returns (L.S memory) { - L.S memory s; - s.a = 5; - return s; - } - function x() public pure returns (L.S memory) { - return L.f(); - } - function y() public pure returns (I.S memory) { - return L.g(); - } - function a1() public pure returns (uint) { S memory s; return L.a(s); } - function a2() public pure returns (uint) { L.S memory s; return L.a(s); } - } - )"; - compileAndRun(sourceCode, 0, "L"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 3)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(4)); - compileAndRun(sourceCode, 0, "C", bytes(), map{ {"L", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 5)); - ABI_CHECK(callContractFunction("x()"), encodeArgs(0, 3)); - ABI_CHECK(callContractFunction("y()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("a1()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("a2()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(enum_referencing) -{ - char const* sourceCode = R"( - interface I { - enum Direction { A, B, Left, Right } - } - library L { - enum Direction { Left, Right } - function f() public pure returns (Direction) { - return Direction.Right; - } - function g() public pure returns (I.Direction) { - return I.Direction.Right; - } - } - contract C is I { - function f() public pure returns (Direction) { - return Direction.Right; - } - function g() public pure returns (I.Direction) { - return I.Direction.Right; - } - function h() public pure returns (L.Direction) { - return L.Direction.Right; - } - function x() public pure returns (L.Direction) { - return L.f(); - } - function y() public pure returns (I.Direction) { - return L.g(); - } - } - )"; - compileAndRun(sourceCode, 0, "L"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("x()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("y()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(inline_member_init) -{ - char const* sourceCode = R"( - contract test { - constructor() public { - m_b = 6; - m_c = 8; - } - uint m_a = 5; - uint m_b; - uint m_c = 7; - function get() public returns (uint a, uint b, uint c){ - a = m_a; - b = m_b; - c = m_c; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("get()"), encodeArgs(5, 6, 8)); -} -BOOST_AUTO_TEST_CASE(inline_member_init_inheritence) -{ - char const* sourceCode = R"( - contract Base { - constructor() public {} - uint m_base = 5; - function getBMember() public returns (uint i) { return m_base; } - } - contract Derived is Base { - constructor() public {} - uint m_derived = 6; - function getDMember() public returns (uint i) { return m_derived; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getBMember()"), encodeArgs(5)); - ABI_CHECK(callContractFunction("getDMember()"), encodeArgs(6)); -} - -BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor) -{ - char const* sourceCode = R"( - contract Base { - uint m_base = 5; - function getBMember() public returns (uint i) { return m_base; } - } - contract Derived is Base { - uint m_derived = 6; - function getDMember() public returns (uint i) { return m_derived; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getBMember()"), encodeArgs(5)); - ABI_CHECK(callContractFunction("getDMember()"), encodeArgs(6)); -} - -BOOST_AUTO_TEST_CASE(external_function) -{ - char const* sourceCode = R"( - contract c { - function f(uint a) public returns (uint) { return a; } - function test(uint a, uint b) external returns (uint r_a, uint r_b) { - r_a = f(a + 7); - r_b = b; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test(uint256,uint256)", 2, 3), encodeArgs(2+7, 3)); - ) -} - -BOOST_AUTO_TEST_CASE(bytes_in_arguments) -{ - char const* sourceCode = R"( - contract c { - uint result; - function f(uint a, uint b) public { result += a + b; } - function g(uint a) public { result *= a; } - function test(uint a, bytes calldata data1, bytes calldata data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) { - r_a = a; - address(this).call(data1); - address(this).call(data2); - r = result; - r_b = b; - l = data1.length; - } - } - )"; - compileAndRun(sourceCode); - - string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); - bytes calldata = encodeArgs( - 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, - u256(innercalldata1.length()), innercalldata1, - u256(innercalldata2.length()), innercalldata2); - ABI_CHECK( - callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), - encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) - ); -} - -BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) -{ - char const* sourceCode = R"( - contract c { - struct Data { uint x; uint y; } - Data[2**10] data; - uint[2**10 + 3] ids; - function setIDStatic(uint id) public { ids[2] = id; } - function setID(uint index, uint id) public { ids[index] = id; } - function setData(uint index, uint x, uint y) public { data[index].x = x; data[index].y = y; } - function getID(uint index) public returns (uint) { return ids[index]; } - function getData(uint index) public returns (uint x, uint y) { x = data[index].x; y = data[index].y; } - function getLengths() public returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("setIDStatic(uint256)", 11), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 2), encodeArgs(11)); - ABI_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 7), encodeArgs(8)); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9), bytes()); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11), bytes()); - ABI_CHECK(callContractFunction("getData(uint256)", 7), encodeArgs(8, 9)); - ABI_CHECK(callContractFunction("getData(uint256)", 8), encodeArgs(10, 11)); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); -} - -BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage) -{ - char const* sourceCode = R"( - contract c { - struct Data { uint x; uint y; } - Data[] data; - uint[] ids; - function setIDStatic(uint id) public { ids[2] = id; } - function setID(uint index, uint id) public { ids[index] = id; } - function setData(uint index, uint x, uint y) public { data[index].x = x; data[index].y = y; } - function getID(uint index) public returns (uint) { return ids[index]; } - function getData(uint index) public returns (uint x, uint y) { x = data[index].x; y = data[index].y; } - function getLengths() public returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } - function setLengths(uint l1, uint l2) public { - while (data.length < l1) - data.push(); - while (ids.length < l2) - ids.push(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(0, 0)); - ABI_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49), bytes()); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(48, 49)); - ABI_CHECK(callContractFunction("setIDStatic(uint256)", 11), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 2), encodeArgs(11)); - ABI_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 7), encodeArgs(8)); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9), bytes()); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11), bytes()); - ABI_CHECK(callContractFunction("getData(uint256)", 7), encodeArgs(8, 9)); - ABI_CHECK(callContractFunction("getData(uint256)", 8), encodeArgs(10, 11)); -} - -BOOST_AUTO_TEST_CASE(fixed_out_of_bounds_array_access) -{ - char const* sourceCode = R"( - contract c { - uint[4] data; - function set(uint index, uint value) public returns (bool) { data[index] = value; return true; } - function get(uint index) public returns (uint) { return data[index]; } - function length() public returns (uint) { return data.length; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 3, 4), encodeArgs(true)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 4, 5), bytes()); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 400, 5), bytes()); - ABI_CHECK(callContractFunction("get(uint256)", 3), encodeArgs(4)); - ABI_CHECK(callContractFunction("get(uint256)", 4), bytes()); - ABI_CHECK(callContractFunction("get(uint256)", 400), bytes()); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ) -} - -BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function enlarge(uint amount) public returns (uint) { - while (data.length < amount) - data.push(); - return data.length; - } - function set(uint index, uint value) public returns (bool) { data[index] = value; return true; } - function get(uint index) public returns (uint) { return data[index]; } - function length() public returns (uint) { return data.length; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("length()"), encodeArgs(0)); - ABI_CHECK(callContractFunction("get(uint256)", 3), bytes()); - ABI_CHECK(callContractFunction("enlarge(uint256)", 4), encodeArgs(4)); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 3, 4), encodeArgs(true)); - ABI_CHECK(callContractFunction("get(uint256)", 3), encodeArgs(4)); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ABI_CHECK(callContractFunction("set(uint256,uint256)", 4, 8), bytes()); - ABI_CHECK(callContractFunction("length()"), encodeArgs(4)); - ); -} - -BOOST_AUTO_TEST_CASE(fixed_array_cleanup) -{ - char const* sourceCode = R"( - contract c { - uint spacer1; - uint spacer2; - uint[20] data; - function fill() public { - for (uint i = 0; i < data.length; ++i) data[i] = i+1; - } - function clear() public { delete data; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ); -} - -BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup) -{ - char const* sourceCode = R"( - contract c { - uint spacer1; - uint spacer2; - uint[3] data; - function fill() public { - for (uint i = 0; i < data.length; ++i) data[i] = i+1; - } - function clear() public { delete data; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ); -} - -BOOST_AUTO_TEST_CASE(dynamic_array_cleanup) -{ - char const* sourceCode = R"( - contract c { - uint[20] spacer; - uint[] dynamic; - function fill() public { - for (uint i = 0; i < 21; ++i) - dynamic.push(i + 1); - } - function halfClear() public { - while (dynamic.length > 5) - dynamic.pop(); - } - function fullClear() public { delete dynamic; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("halfClear()"), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fullClear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ); -} - -BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) -{ - char const* sourceCode = R"( - contract c { - struct s { uint[][] d; } - s[] data; - function fill() public returns (uint) { - while (data.length < 3) - data.push(); - while (data[2].d.length < 4) - data[2].d.push(); - while (data[2].d[3].length < 5) - data[2].d[3].push(); - data[2].d[3][4] = 8; - return data[2].d[3][4]; - } - function clear() public { delete data; } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) -{ - char const* sourceCode = R"( - contract c { - uint[] data1; - uint[] data2; - function setData1(uint length, uint index, uint value) public { - data1 = new uint[](length); - if (index < length) - data1[index] = value; - } - function copyStorageStorage() public { data2 = data1; } - function getData2(uint index) public returns (uint len, uint val) { - len = data2.length; if (index < len) val = data2[index]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4), bytes()); - ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes()); - ABI_CHECK(callContractFunction("getData2(uint256)", 5), encodeArgs(10, 4)); - ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0), bytes()); - ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes()); - ABI_CHECK(callContractFunction("getData2(uint256)", 0), encodeArgs(0, 0)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static) -{ - char const* sourceCode = R"( - contract c { - uint[40] data1; - uint[20] data2; - function test() public returns (uint x, uint y){ - data1[30] = 4; - data1[2] = 7; - data1[3] = 9; - data2[3] = 8; - data1 = data2; - x = data1[3]; - y = data1[30]; // should be cleared - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(8, 0)); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic) -{ - char const* sourceCode = R"( - contract c { - uint[9] data1; - uint[] data2; - function test() public returns (uint x, uint y){ - data1[8] = 4; - data2 = data1; - x = data2.length; - y = data2[8]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(9, 4)); -} - -BOOST_AUTO_TEST_CASE(array_copy_different_packing) -{ - char const* sourceCode = R"( - contract c { - bytes8[] data1; // 4 per slot - bytes10[] data2; // 3 per slot - function test() public returns (bytes10 a, bytes10 b, bytes10 c, bytes10 d, bytes10 e) { - data1 = new bytes8[](9); - for (uint i = 0; i < data1.length; ++i) - data1[i] = bytes8(uint64(i)); - data2 = data1; - a = data2[1]; - b = data2[2]; - c = data2[3]; - d = data2[4]; - e = data2[5]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000001")), - asString(fromHex("0000000000000002")), - asString(fromHex("0000000000000003")), - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000005")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_target_simple) -{ - char const* sourceCode = R"( - contract c { - bytes8[9] data1; // 4 per slot - bytes17[10] data2; // 1 per slot, no offset counter - function test() public returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) { - for (uint i = 0; i < data1.length; ++i) - data1[i] = bytes8(uint64(i)); - data2[8] = data2[9] = bytes8(uint64(2)); - data2 = data1; - a = data2[1]; - b = data2[2]; - c = data2[3]; - d = data2[4]; - e = data2[9]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000001")), - asString(fromHex("0000000000000002")), - asString(fromHex("0000000000000003")), - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000000")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_target_leftover) -{ - // test that leftover elements in the last slot of target are correctly cleared during assignment - char const* sourceCode = R"( - contract c { - byte[10] data1; - bytes2[32] data2; - function test() public returns (uint check, uint res1, uint res2) { - uint i; - for (i = 0; i < data2.length; ++i) - data2[i] = 0xffff; - check = uint(uint16(data2[31])) * 0x10000 | uint(uint16(data2[14])); - for (i = 0; i < data1.length; ++i) - data1[i] = byte(uint8(1 + i)); - data2 = data1; - for (i = 0; i < 16; ++i) - res1 |= uint(uint16(data2[i])) * 0x10000**i; - for (i = 0; i < 16; ++i) - res2 |= uint(uint16(data2[16 + i])) * 0x10000**i; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256("0xffffffff"), - asString(fromHex("0000000000000000""000000000a000900""0800070006000500""0400030002000100")), - asString(fromHex("0000000000000000""0000000000000000""0000000000000000""0000000000000000")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_target_leftover2) -{ - // since the copy always copies whole slots, we have to make sure that the source size maxes - // out a whole slot and at the same time there are still elements left in the target at that point - char const* sourceCode = R"( - contract c { - bytes8[4] data1; // fits into one slot - bytes10[6] data2; // 4 elements need two slots - function test() public returns (bytes10 r1, bytes10 r2, bytes10 r3) { - data1[0] = bytes8(uint64(1)); - data1[1] = bytes8(uint64(2)); - data1[2] = bytes8(uint64(3)); - data1[3] = bytes8(uint64(4)); - for (uint i = 0; i < data2.length; ++i) - data2[i] = bytes10(uint80(0xffff00 | (1 + i))); - data2 = data1; - r1 = data2[3]; - r2 = data2[4]; - r3 = data2[5]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - asString(fromHex("0000000000000004")), - asString(fromHex("0000000000000000")), - asString(fromHex("0000000000000000")) - )); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) -{ - char const* sourceCode = R"( - contract c { - struct Data { uint x; uint y; } - Data[] data1; - Data[] data2; - function test() public returns (uint x, uint y) { - while (data1.length < 9) - data1.push(); - data1[8].x = 4; - data1[8].y = 5; - data2 = data1; - x = data2[8].x; - y = data2[8].y; - while (data1.length > 0) - data1.pop(); - data2 = data1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(4, 5)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_abi) -{ - // NOTE: This does not really test copying from storage to ABI directly, - // because it will always copy to memory first. - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract c { - uint8[] x; - uint16[] y; - uint24[] z; - uint24[][] w; - function test1() public returns (uint8[] memory) { - for (uint i = 0; i < 101; ++i) - x.push(uint8(i)); - return x; - } - function test2() public returns (uint16[] memory) { - for (uint i = 0; i < 101; ++i) - y.push(uint16(i)); - return y; - } - function test3() public returns (uint24[] memory) { - for (uint i = 0; i < 101; ++i) - z.push(uint24(i)); - return z; - } - function test4() public returns (uint24[][] memory) { - w = new uint24[][](5); - for (uint i = 0; i < 5; ++i) - for (uint j = 0; j < 101; ++j) - w[i].push(uint24(j)); - return w; - } - } - )"; - compileAndRun(sourceCode); - bytes valueSequence; - for (size_t i = 0; i < 101; ++i) - valueSequence += toBigEndian(u256(i)); - ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test4()"), - encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence - ); -} - -BOOST_AUTO_TEST_CASE(array_copy_storage_abi_signed) -{ - // NOTE: This does not really test copying from storage to ABI directly, - // because it will always copy to memory first. - char const* sourceCode = R"( - contract c { - int16[] x; - function test() public returns (int16[] memory) { - x.push(int16(-1)); - x.push(int16(-1)); - x.push(int16(8)); - x.push(int16(-16)); - x.push(int16(-2)); - x.push(int16(6)); - x.push(int16(8)); - x.push(int16(-1)); - return x; - } - } - )"; - compileAndRun(sourceCode); - bytes valueSequence; - ABI_CHECK(callContractFunction("test()"), encodeArgs(0x20, 8, - u256(-1), - u256(-1), - u256(8), - u256(-16), - u256(-2), - u256(6), - u256(8), - u256(-1) - )); -} - -BOOST_AUTO_TEST_CASE(array_push) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (uint x, uint y, uint z, uint l) { - data.push(5); - x = data[0]; - data.push(4); - y = data[1]; - data.push(3); - l = data.length; - z = data[2]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(5, 4, 3, 3)); -} - -BOOST_AUTO_TEST_CASE(array_push_struct) -{ - char const* sourceCode = R"( - contract c { - struct S { uint16 a; uint16 b; uint16[3] c; uint16[] d; } - S[] data; - function test() public returns (uint16, uint16, uint16, uint16) { - S memory s; - s.a = 2; - s.b = 3; - s.c[2] = 4; - s.d = new uint16[](4); - s.d[2] = 5; - data.push(s); - return (data[0].a, data[0].b, data[0].c[2], data[0].d[2]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 3, 4, 5)); -} - -BOOST_AUTO_TEST_CASE(array_push_packed_array) -{ - char const* sourceCode = R"( - contract c { - uint80[] x; - function test() public returns (uint80, uint80, uint80, uint80) { - x.push(1); - x.push(2); - x.push(3); - x.push(4); - x.push(5); - x.pop(); - return (x[0], x[1], x[2], x[3]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3, 4)); -} - -BOOST_AUTO_TEST_CASE(byte_array_push) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bool x) { - data.push(0x05); - if (data.length != 1) return true; - if (data[0] != 0x05) return true; - data.push(0x04); - if (data[1] != 0x04) return true; - data.push(0x03); - uint l = data.length; - if (data[2] != 0x03) return true; - if (l != 0x03) return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(byte_array_push_transition) -{ - // Tests transition between short and long encoding - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (uint) { - for (uint8 i = 1; i < 40; i++) - { - data.push(byte(i)); - if (data.length != i) return 0x1000 + i; - if (data[data.length - 1] != byte(i)) return i; - } - for (uint8 i = 1; i < 40; i++) - if (data[i - 1] != byte(i)) return 0x1000000 + i; - return 0; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(array_pop) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (uint x, uint l) { - data.push(7); - data.push(3); - x = data.length; - data.pop(); - x = data.length; - data.pop(); - l = data.length; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 0)); -} - -BOOST_AUTO_TEST_CASE(array_pop_uint16_transition) -{ - char const* sourceCode = R"( - contract c { - uint16[] data; - function test() public returns (uint16 x, uint16 y, uint16 z) { - for (uint i = 1; i <= 48; i++) - data.push(uint16(i)); - for (uint j = 1; j <= 10; j++) - data.pop(); - x = data[data.length - 1]; - for (uint k = 1; k <= 10; k++) - data.pop(); - y = data[data.length - 1]; - for (uint l = 1; l <= 10; l++) - data.pop(); - z = data[data.length - 1]; - for (uint m = 1; m <= 18; m++) - data.pop(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - uint256 c; - uint24[] data; - function test() public returns (uint24 x, uint24 y) { - for (uint i = 1; i <= 30; i++) - data.push(uint24(i)); - for (uint j = 1; j <= 10; j++) - data.pop(); - x = data[data.length - 1]; - for (uint k = 1; k <= 10; k++) - data.pop(); - y = data[data.length - 1]; - for (uint l = 1; l <= 10; l++) - data.pop(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_pop_array_transition) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - uint256 c; - uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - uint16[][] data; - function test() public returns (uint x, uint y, uint z) { - for (uint i = 1; i <= 48; i++) - data.push(inner); - for (uint j = 1; j <= 10; j++) - data.pop(); - x = data[data.length - 1][0]; - for (uint k = 1; k <= 10; k++) - data.pop(); - y = data[data.length - 1][1]; - for (uint l = 1; l <= 10; l++) - data.pop(); - z = data[data.length - 1][2]; - for (uint m = 1; m <= 18; m++) - data.pop(); - delete inner; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(array_pop_empty_exception) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public returns (bool) { - data.pop(); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(array_pop_storage_empty) -{ - char const* sourceCode = R"( - contract c { - uint[] data; - function test() public { - data.push(7); - data.pop(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (uint x, uint y, uint l) { - data.push(0x07); - data.push(0x03); - x = data.length; - data.pop(); - data.pop(); - data.push(0x02); - y = data.length; - l = data.length; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 1, 1)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_empty_exception) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - uint256 c; - bytes data; - function test() public returns (bool) { - data.pop(); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public { - data.push(0x07); - data.push(0x05); - data.push(0x03); - data.pop(); - data.pop(); - data.pop(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - uint256 c; - bytes data; - function test() public returns (bool) { - for (uint8 i = 0; i <= 40; i++) - data.push(byte(i+1)); - for (int8 j = 40; j >= 0; j--) { - require(data[uint8(j)] == byte(j+1)); - require(data.length == uint8(j+1)); - data.pop(); - } - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) -{ - char const* sourceCode = R"( - contract c { - uint256 a; - uint256 b; - bytes data; - function test() public { - for (uint8 i = 0; i <= 40; i++) - data.push(0x03); - for (uint8 j = 0; j <= 40; j++) { - assembly { - mstore(0, "garbage") - } - data.pop(); - } - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_masking_long) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bytes memory) { - for (uint i = 0; i < 34; i++) - data.push(0x03); - data.pop(); - return data; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256(0x20), - u256(33), - asString(fromHex("0303030303030303030303030303030303030303030303030303030303030303")), - asString(fromHex("03")) - )); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_copy_long) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test() public returns (bytes memory) { - for (uint i = 0; i < 33; i++) - data.push(0x03); - for (uint j = 0; j < 4; j++) - data.pop(); - return data; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs( - u256(0x20), - u256(29), - asString(fromHex("0303030303030303030303030303030303030303030303030303030303")) - )); -} - -BOOST_AUTO_TEST_CASE(array_pop_isolated) -{ - char const* sourceCode = R"( - // This tests that the compiler knows the correct size of the function on the stack. - contract c { - uint[] data; - function test() public returns (uint x) { - x = 2; - data.pop; - x = 3; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(byte_array_pop_isolated) -{ - char const* sourceCode = R"( - // This tests that the compiler knows the correct size of the function on the stack. - contract c { - bytes data; - function test() public returns (uint x) { - x = 2; - data.pop; - x = 3; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(external_array_args) -{ - char const* sourceCode = R"( - contract c { - function test(uint[8] calldata a, uint[] calldata b, uint[5] calldata c, uint a_index, uint b_index, uint c_index) - external returns (uint av, uint bv, uint cv) { - av = a[a_index]; - bv = b[b_index]; - cv = c[c_index]; - } - } - )"; - compileAndRun(sourceCode); - bytes params = encodeArgs( - 1, 2, 3, 4, 5, 6, 7, 8, // a - 32 * (8 + 1 + 5 + 1 + 1 + 1), // offset to b - 21, 22, 23, 24, 25, // c - 0, 1, 2, // (a,b,c)_index - 3, // b.length - 11, 12, 13 // b - ); - ABI_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params), encodeArgs(1, 12, 23)); -} - -BOOST_AUTO_TEST_CASE(bytes_index_access) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function direct(bytes calldata arg, uint index) external returns (uint) { - return uint(uint8(arg[index])); - } - function storageCopyRead(bytes calldata arg, uint index) external returns (uint) { - data = arg; - return uint(uint8(data[index])); - } - function storageWrite() external returns (uint) { - data = new bytes(35); - data[31] = 0x77; - data[32] = 0x14; - - data[31] = 0x01; - data[31] |= 0x08; - data[30] = 0x01; - data[32] = 0x03; - return uint(uint8(data[30])) * 0x100 | uint(uint8(data[31])) * 0x10 | uint(uint8(data[32])); - } - } - )"; - compileAndRun(sourceCode); - string array{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33}; - ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); -} - -BOOST_AUTO_TEST_CASE(bytes_delete_element) -{ - char const* sourceCode = R"( - contract c { - bytes data; - function test1() external returns (bool) { - data = new bytes(100); - for (uint i = 0; i < data.length; i++) - data[i] = byte(uint8(i)); - delete data[94]; - delete data[96]; - delete data[98]; - return data[94] == 0 && uint8(data[95]) == 95 && data[96] == 0 && uint8(data[97]) == 97; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test1()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) -{ - char const* sourceCode = R"( - contract c { - uint[9] m_data; - uint[] m_data_dyn; - uint8[][] m_byte_data; - function store(uint[9] calldata a, uint8[3][] calldata b) external returns (uint8) { - m_data = a; - m_data_dyn = a; - m_byte_data = b; - return b[3][1]; // note that access and declaration are reversed to each other - } - function retrieve() public returns (uint a, uint b, uint c, uint d, uint e, uint f, uint g) { - a = m_data.length; - b = m_data[7]; - c = m_data_dyn.length; - d = m_data_dyn[7]; - e = m_byte_data.length; - f = m_byte_data[3].length; - g = m_byte_data[3][1]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs( - 21, 22, 23, 24, 25, 26, 27, 28, 29, // a - u256(32 * (9 + 1)), - 4, // size of b - 1, 2, 3, // b[0] - 11, 12, 13, // b[1] - 21, 22, 23, // b[2] - 31, 32, 33 // b[3] - )), encodeArgs(32)); - ABI_CHECK(callContractFunction("retrieve()"), encodeArgs( - 9, 28, 9, 28, - 4, 3, 32)); -} - -BOOST_AUTO_TEST_CASE(array_copy_nested_array) -{ - char const* sourceCode = R"( - contract c { - uint[4][] a; - uint[10][] b; - uint[][] c; - function test(uint[2][] calldata d) external returns (uint) { - a = d; - b = a; - c = b; - return c[1][1] | c[1][2] | c[1][3] | c[1][4]; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test(uint256[2][])", encodeArgs( - 32, 3, - 7, 8, - 9, 10, - 11, 12 - )), encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(array_copy_including_mapping) -{ - char const* sourceCode = R"( - contract c { - mapping(uint=>uint)[90][] large; - mapping(uint=>uint)[3][] small; - function test() public returns (uint r) { - for (uint i = 0; i < 7; i++) { - large.push(); - small.push(); - } - large[3][2][0] = 2; - large[1] = large[3]; - small[3][2][0] = 2; - small[1] = small[2]; - r = (( - small[3][2][0] * 0x100 | - small[1][2][0]) * 0x100 | - large[3][2][0]) * 0x100 | - large[1][2][0]; - delete small; - delete large; - - } - function clear() public returns (uint, uint) { - for (uint i = 0; i < 7; i++) { - large.push(); - small.push(); - } - small[3][2][0] = 0; - large[3][2][0] = 0; - while (small.length > 0) - small.pop(); - while (large.length > 0) - large.pop(); - return (small.length, large.length); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(0x02000200)); - // storage is not empty because we cannot delete the mappings - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), encodeArgs(0, 0)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(swap_in_storage_overwrite) -{ - // This tests a swap in storage which does not work as one - // might expect because we do not have temporary storage. - // (x, y) = (y, x) is the same as - // y = x; - // x = y; - char const* sourceCode = R"( - contract c { - struct S { uint a; uint b; } - S public x; - S public y; - function set() public { - x.a = 1; x.b = 2; - y.a = 3; y.b = 4; - } - function swap() public { - (x, y) = (y, x); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0), u256(0))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(0), u256(0))); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1), u256(2))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(3), u256(4))); - ABI_CHECK(callContractFunction("swap()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1), u256(2))); - ABI_CHECK(callContractFunction("y()"), encodeArgs(u256(1), u256(2))); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint i) public - { - m_i = i; - } - uint public m_i; - } - contract Derived is Base { - constructor(uint i) Base(i) public - {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint j) public - { - m_i = j; - } - uint public m_i; - } - contract Base1 is Base { - constructor(uint k) Base(k) public {} - } - contract Derived is Base, Base1 { - constructor(uint i) Base1(i) public - {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap) -{ - char const* sourceCode = R"( - contract Base { - constructor(uint i) public - { - m_i = i; - } - uint public m_i; - } - abstract contract Base1 is Base { - constructor(uint k) public {} - } - contract Derived is Base, Base1 { - constructor(uint i) Base(i) Base1(7) public {} - } - contract Final is Derived(4) { - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("m_i()"), encodeArgs(4)); -} - -BOOST_AUTO_TEST_CASE(simple_constant_variables_test) -{ - char const* sourceCode = R"( - contract Foo { - function getX() public returns (uint r) { return x; } - uint constant x = 56; - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getX()"), encodeArgs(56)); -} - -BOOST_AUTO_TEST_CASE(constant_variables) -{ - char const* sourceCode = R"( - contract Foo { - uint constant x = 56; - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } - ActionChoices constant choices = ActionChoices.GoLeft; - bytes32 constant st = "abc\x00\xff__"; - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ) -} - -BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_expression) -{ - char const* sourceCode = R"( - contract C { - uint constant x = 0x123 + 0x456; - function f() public returns (uint) { return x + 1; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x123 + 0x456 + 1)); -} - -BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) -{ - char const* sourceCode = R"( - contract C { - bytes32 constant x = keccak256("abc"); - function f() public returns (bytes32) { return x; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(util::keccak256("abc"))); -} - -// Disabled until https://github.com/ethereum/solidity/issues/715 is implemented -//BOOST_AUTO_TEST_CASE(assignment_to_const_array_vars) -//{ -// char const* sourceCode = R"( -// contract C { -// uint[3] constant x = [uint(1), 2, 3]; -// uint constant y = x[0] + x[1] + x[2]; -// function f() public returns (uint) { return y; } -// } -// )"; -// compileAndRun(sourceCode); -// ABI_CHECK(callContractFunction("f()"), encodeArgs(1 + 2 + 3)); -//} - -// Disabled until https://github.com/ethereum/solidity/issues/715 is implemented -//BOOST_AUTO_TEST_CASE(constant_struct) -//{ -// char const* sourceCode = R"( -// contract C { -// struct S { uint x; uint[] y; } -// S constant x = S(5, new uint[](4)); -// function f() public returns (uint) { return x.x; } -// } -// )"; -// compileAndRun(sourceCode); -// ABI_CHECK(callContractFunction("f()"), encodeArgs(5)); -//} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_uint) -{ - char const* sourceCode = R"( - contract C { - struct str { uint8 a; uint16 b; uint248 c; } - str data; - function test() public returns (uint) { - data.a = 2; - if (data.a != 2) return 2; - data.b = 0xabcd; - if (data.b != 0xabcd) return 3; - data.c = 0x1234567890; - if (data.c != 0x1234567890) return 4; - if (data.a != 2) return 5; - data.a = 8; - if (data.a != 8) return 6; - if (data.b != 0xabcd) return 7; - data.b = 0xdcab; - if (data.b != 0xdcab) return 8; - if (data.c != 0x1234567890) return 9; - data.c = 0x9876543210; - if (data.c != 0x9876543210) return 10; - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_enum) -{ - char const* sourceCode = R"( - contract C { - enum small { A, B, C, D } - enum larger { A, B, C, D, E} - struct str { small a; small b; larger c; larger d; } - str data; - function test() public returns (uint) { - data.a = small.B; - if (data.a != small.B) return 2; - data.b = small.C; - if (data.b != small.C) return 3; - data.c = larger.D; - if (data.c != larger.D) return 4; - if (data.a != small.B) return 5; - data.a = small.C; - if (data.a != small.C) return 6; - if (data.b != small.C) return 7; - data.b = small.D; - if (data.b != small.D) return 8; - if (data.c != larger.D) return 9; - data.c = larger.B; - if (data.c != larger.B) return 10; - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_bytes) -{ - char const* sourceCode = R"( - contract C { - struct s1 { byte a; byte b; bytes10 c; bytes9 d; bytes10 e; } - struct s2 { byte a; s1 inner; byte b; byte c; } - byte x; - s2 data; - byte y; - function test() public returns (bool) { - x = 0x01; - data.a = 0x02; - data.inner.a = 0x03; - data.inner.b = 0x04; - data.inner.c = "1234567890"; - data.inner.d = "123456789"; - data.inner.e = "abcdefghij"; - data.b = 0x05; - data.c = byte(0x06); - y = 0x07; - return x == 0x01 && data.a == 0x02 && data.inner.a == 0x03 && data.inner.b == 0x04 && - data.inner.c == "1234567890" && data.inner.d == "123456789" && - data.inner.e == "abcdefghij" && data.b == 0x05 && data.c == byte(0x06) && y == 0x07; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) -{ - char const* sourceCode = R"( - contract C { - struct str { uint8 a; uint16 b; uint8 c; } - uint8 x; - uint16 y; - str data; - function test() public returns (uint) { - x = 1; - y = 2; - data.a = 2; - data.b = 0xabcd; - data.c = 0xfa; - if (x != 1 || y != 2 || data.a != 2 || data.b != 0xabcd || data.c != 0xfa) - return 2; - delete y; - delete data.b; - if (x != 1 || y != 0 || data.a != 2 || data.b != 0 || data.c != 0xfa) - return 3; - delete x; - delete data; - return 1; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first) -{ - char const* sourceCode = R"( - contract test { - function f(uint k) public returns(uint d) { return k; } - function f(uint a, uint b) public returns(uint d) { return a + b; } - function g() public returns(uint d) { return f(3); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ) -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_second) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) public returns(uint d) { return a + b; } - function f(uint k) public returns(uint d) { return k; } - function g() public returns(uint d) { return f(3, 7); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ) -} - -BOOST_AUTO_TEST_CASE(overloaded_function_call_with_if_else) -{ - char const* sourceCode = R"( - contract test { - function f(uint a, uint b) public returns(uint d) { return a + b; } - function f(uint k) public returns(uint d) { return k; } - function g(bool flag) public returns(uint d) { - if (flag) - return f(3); - else - return f(3, 7); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(3)); - ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs(10)); - ) -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_direct) -{ - char const* sourceCode = R"( - contract B { function f() public returns(uint) { return 10; } } - contract C is B { - function f(uint i) public returns(uint) { return 2 * i; } - function g() public returns(uint) { return f(1); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(derived_overload_base_function_indirect) -{ - char const* sourceCode = R"( - contract A { function f(uint a) public returns(uint) { return 2 * a; } } - contract B { function f() public returns(uint) { return 10; } } - contract C is A, B { - function g() public returns(uint) { return f(); } - function h() public returns(uint) { return f(1); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(super_overload) -{ - char const* sourceCode = R"( - contract A { function f(uint a) public returns(uint) { return 2 * a; } } - contract B { function f(bool b) public returns(uint) { return 10; } } - contract C is A, B { - function g() public returns(uint) { return super.f(true); } - function h() public returns(uint) { return super.f(1); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(10)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(gasleft_shadow_resolution) -{ - char const* sourceCode = R"( - contract C { - function gasleft() public returns(uint256) { return 0; } - function f() public returns(uint256) { return gasleft(); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); - ) -} - -BOOST_AUTO_TEST_CASE(bool_conversion) -{ - char const* sourceCode = R"( - contract C { - function f(bool _b) public returns(uint) { - if (_b) - return 1; - else - return 0; - } - function g(bool _in) public returns (bool _out) { - _out = _in; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(bool)", 0), encodeArgs(0)); - ABI_CHECK(callContractFunction("f(bool)", 1), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 0), encodeArgs(0)); - ABI_CHECK(callContractFunction("g(bool)", 1), encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(packed_storage_signed) -{ - char const* sourceCode = R"( - contract C { - int8 a; - uint8 b; - int8 c; - uint8 d; - function test() public returns (uint x1, uint x2, uint x3, uint x4) { - a = -2; - b = -uint8(a) * 2; - c = a * int8(120) * int8(121); - x1 = uint(a); - x2 = b; - x3 = uint(c); - x4 = d; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(-2), u256(4), u256(-112), u256(0))); -} - -BOOST_AUTO_TEST_CASE(external_types_in_calls) -{ - char const* sourceCode = R"( - contract C1 { C1 public bla; constructor(C1 x) public { bla = x; } } - contract C { - function test() public returns (C1 x, C1 y) { - C1 c = new C1(C1(9)); - x = c.bla(); - y = this.t1(C1(7)); - } - function t1(C1 a) public returns (C1) { return a; } - function t2() public returns (C1) { return C1(9); } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(9), u256(7))); - ABI_CHECK(callContractFunction("t2()"), encodeArgs(u256(9))); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_compared) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function test_eq() public returns (bool) { - X garbled; - assembly { - garbled := 5 - } - return garbled == garbled; - } - function test_eq_ok() public returns (bool) { - X garbled = X.A; - return garbled == garbled; - } - function test_neq() public returns (bool) { - X garbled; - assembly { - garbled := 5 - } - return garbled != garbled; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test_eq_ok()"), encodeArgs(u256(1))); - // both should throw - ABI_CHECK(callContractFunction("test_eq()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_neq()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_logged) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - event Log(X); - - function test_log() public returns (uint) { - X garbled = X.A; - assembly { - garbled := 5 - } - emit Log(garbled); - return 1; - } - function test_log_ok() public returns (uint) { - X x = X.A; - emit Log(x); - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test_log_ok()"), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_REQUIRE_EQUAL(logTopic(0, 0), util::keccak256(string("Log(uint8)"))); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0))); - - // should throw - ABI_CHECK(callContractFunction("test_log()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_stored) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - X public x; - - function test_store() public returns (uint) { - X garbled = X.A; - assembly { - garbled := 5 - } - x = garbled; - return 1; - } - function test_store_ok() public returns (uint) { - x = X.A; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test_store_ok()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - - // should throw - ABI_CHECK(callContractFunction("test_store()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(invalid_enum_as_external_ret) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function test_return() public returns (X) { - X garbled; - assembly { - garbled := 5 - } - return garbled; - } - function test_inline_assignment() public returns (X _ret) { - assembly { - _ret := 5 - } - } - function test_assignment() public returns (X _ret) { - X tmp; - assembly { - tmp := 5 - } - _ret = tmp; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - // both should throw - ABI_CHECK(callContractFunction("test_return()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_inline_assignment()"), encodeArgs()); - ABI_CHECK(callContractFunction("test_assignment()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg) -{ - char const* sourceCode = R"( - contract C { - enum X { A, B } - - function tested (X x) public returns (uint) { - return 1; - } - - function test() public returns (uint) { - X garbled; - - assembly { - garbled := 5 - } - - return this.tested(garbled); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // should throw - ABI_CHECK(callContractFunction("test()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - testStruct data1; - testStruct data2; - testStruct data3; - constructor() public - { - data1.m_value = 2; - } - function assign() public returns (uint ret_local, uint ret_global, uint ret_global3, uint ret_global1) - { - testStruct storage x = data1; //x is a reference data1.m_value == 2 as well as x.m_value = 2 - data2 = data1; // should copy data. data2.m_value == 2 - - ret_local = x.m_value; // = 2 - ret_global = data2.m_value; // = 2 - - x.m_value = 3; - data3 = x; //should copy the data. data3.m_value == 3 - ret_global3 = data3.m_value; // = 3 - ret_global1 = data1.m_value; // = 3. Changed due to the assignment to x.m_value - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("assign()"), encodeArgs(2, 2, 3, 3)); -} - -BOOST_AUTO_TEST_CASE(struct_delete_member) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - testStruct data1; - constructor() public - { - data1.m_value = 2; - } - function deleteMember() public returns (uint ret_value) - { - testStruct storage x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 - x.m_value = 4; - delete x.m_value; - ret_value = data1.m_value; - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("deleteMember()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) -{ - char const* sourceCode = R"( - contract test { - struct testStruct - { - uint m_value; - } - mapping (uint => testStruct) campaigns; - - constructor() public - { - campaigns[0].m_value = 2; - } - function deleteIt() public returns (uint) - { - delete campaigns[0]; - return campaigns[0].m_value; - } - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("deleteIt()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) -{ - char const* sourceCode = R"( - contract A { - uint[3] arr; - bool public test = false; - function getElement(uint i) public returns (uint) - { - return arr[i]; - } - function testIt() public returns (bool) - { - uint i = this.getElement(5); - test = true; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "A"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("testIt()"), encodeArgs()); - ABI_CHECK(callContractFunction("test()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) -{ - char const* sourceCode = R"( - contract A { - constructor() public - { - address(this).call("123"); - } - } - contract B { - uint public test = 1; - function testIt() public - { - A a = new A(); - ++test; - } - } - )"; - compileAndRun(sourceCode, 0, "B"); - - ABI_CHECK(callContractFunction("testIt()"), encodeArgs()); - ABI_CHECK(callContractFunction("test()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) -{ - char const* sourceCode = R"( - contract A { - uint public test = 1; - uint[3] arr; - constructor() public - { - uint index = 5; - test = arr[index]; - ++test; - } - } - )"; - ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs()); - BOOST_CHECK(!m_transactionSuccessful); -} - -BOOST_AUTO_TEST_CASE(positive_integers_to_signed) -{ - char const* sourceCode = R"( - contract test { - int8 public x = 2; - int8 public y = 127; - int16 public q = 250; - } - )"; - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("y()"), encodeArgs(127)); - ABI_CHECK(callContractFunction("q()"), encodeArgs(250)); -} - -BOOST_AUTO_TEST_CASE(failing_send) -{ - char const* sourceCode = R"( - contract Helper { - uint[] data; - fallback () external { - data[9]; // trigger exception - } - } - contract Main { - constructor() public payable {} - function callHelper(address payable _a) public returns (bool r, uint bal) { - r = !_a.send(5); - bal = address(this).balance; - } - } - )"; - compileAndRun(sourceCode, 0, "Helper"); - u160 const c_helperAddress = m_contractAddress; - compileAndRun(sourceCode, 20, "Main"); - BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); -} - -BOOST_AUTO_TEST_CASE(send_zero_ether) -{ - // Sending zero ether to a contract should still invoke the receive ether function - // (it previously did not because the gas stipend was not provided by the EVM) - char const* sourceCode = R"( - contract Receiver { - receive () external payable { - } - } - contract Main { - constructor() public payable {} - function s() public returns (bool) { - Receiver r = new Receiver(); - return address(r).send(0); - } - } - )"; - compileAndRun(sourceCode, 20, "Main"); - BOOST_REQUIRE(callContractFunction("s()") == encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(reusing_memory) -{ - // Invoke some features that use memory and test that they do not interfere with each other. - char const* sourceCode = R"( - contract Helper { - uint public flag; - constructor(uint x) public { - flag = x; - } - } - contract Main { - mapping(uint => uint) map; - function f(uint x) public returns (uint) { - map[x] = x; - return (new Helper(uint(keccak256(abi.encodePacked(this.g(map[x])))))).flag(); - } - function g(uint a) public returns (uint) - { - return map[a]; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(util::keccak256(util::toBigEndian(u256(0x34))))); -} - -BOOST_AUTO_TEST_CASE(return_string) -{ - char const* sourceCode = R"( - contract Main { - string public s; - function set(string calldata _s) external { - s = _s; - } - function get1() public returns (string memory r) { - return s; - } - function get2() public returns (string memory r) { - r = s; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s("Julia"); - bytes args = encodeArgs(u256(0x20), u256(s.length()), s); - BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs()); - ABI_CHECK(callContractFunction("get1()"), args); - ABI_CHECK(callContractFunction("get2()"), args); - ABI_CHECK(callContractFunction("s()"), args); -} - -BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes) -{ - char const* sourceCode = R"( - contract Main { - string public s1; - string public s2; - function set(string calldata _s1, uint x, string calldata _s2) external returns (uint) { - s1 = _s1; - s2 = _s2; - return x; - } - function get() public returns (string memory r1, string memory r2) { - r1 = s1; - r2 = s2; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s1( - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - ); - string s2( - "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" - "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" - "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" - "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" - "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" - ); - vector lengths{0, 30, 32, 63, 64, 65, 210, 300}; - for (auto l1: lengths) - for (auto l2: lengths) - { - bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); - bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); - bytes args = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; - BOOST_REQUIRE( - callContractFunction("set(string,uint256,string)", asString(args)) == - encodeArgs(u256(l1)) - ); - bytes result = encodeArgs(u256(0x40), u256(0x40 + dyn1.size())) + dyn1 + dyn2; - ABI_CHECK(callContractFunction("get()"), result); - ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1); - ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2); - } -} - -BOOST_AUTO_TEST_CASE(accessor_involving_strings) -{ - char const* sourceCode = R"( - contract Main { - struct stringData { string a; uint b; string c; } - mapping(uint => stringData[]) public data; - function set(uint x, uint y, string calldata a, uint b, string calldata c) external returns (bool) { - while (data[x].length < y + 1) - data[x].push(); - data[x][y].a = a; - data[x][y].b = b; - data[x][y].c = c; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); - bytes s1Data = encodeArgs(u256(s1.length()), s1); - bytes s2Data = encodeArgs(u256(s2.length()), s2); - u256 b = 765; - u256 x = 7; - u256 y = 123; - bytes args = encodeArgs(x, y, u256(0xa0), b, u256(0xa0 + s1Data.size()), s1Data, s2Data); - bytes result = encodeArgs(u256(0x60), b, u256(0x60 + s1Data.size()), s1Data, s2Data); - BOOST_REQUIRE(callContractFunction("set(uint256,uint256,string,uint256,string)", asString(args)) == encodeArgs(true)); - BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); -} - -BOOST_AUTO_TEST_CASE(bytes_in_function_calls) -{ - char const* sourceCode = R"( - contract Main { - string public s1; - string public s2; - function set(string memory _s1, uint x, string memory _s2) public returns (uint) { - s1 = _s1; - s2 = _s2; - return x; - } - function setIndirectFromMemory(string memory _s1, uint x, string memory _s2) public returns (uint) { - return this.set(_s1, x, _s2); - } - function setIndirectFromCalldata(string calldata _s1, uint x, string calldata _s2) external returns (uint) { - return this.set(_s1, x, _s2); - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); - vector lengths{0, 31, 64, 65}; - for (auto l1: lengths) - for (auto l2: lengths) - { - bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); - bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); - bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; - BOOST_REQUIRE( - callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) == - encodeArgs(u256(l1)) - ); - ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1); - ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2); - // swapped - bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1; - BOOST_REQUIRE( - callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) == - encodeArgs(u256(l1)) - ); - ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn2); - ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn1); - } -} - -BOOST_AUTO_TEST_CASE(return_bytes_internal) -{ - char const* sourceCode = R"( - contract Main { - bytes s1; - function doSet(bytes memory _s1) public returns (bytes memory _r1) { - s1 = _s1; - _r1 = s1; - } - function set(bytes calldata _s1) external returns (uint _r, bytes memory _r1) { - _r1 = doSet(_s1); - _r = _r1.length; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - vector lengths{0, 31, 64, 65}; - for (auto l1: lengths) - { - bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); - bytes args1 = encodeArgs(u256(0x20)) + dyn1; - BOOST_REQUIRE( - callContractFunction("set(bytes)", asString(args1)) == - encodeArgs(u256(l1), u256(0x40)) + dyn1 - ); - } -} - -BOOST_AUTO_TEST_CASE(bytes_index_access_memory) -{ - char const* sourceCode = R"( - contract Main { - function f(bytes memory _s1, uint i1, uint i2, uint i3) public returns (byte c1, byte c2, byte c3) { - c1 = _s1[i1]; - c2 = intern(_s1, i2); - c3 = internIndirect(_s1)[i3]; - } - function intern(bytes memory _s1, uint i) public returns (byte c) { - return _s1[i]; - } - function internIndirect(bytes memory _s1) public returns (bytes memory) { - return _s1; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - bytes dyn1 = encodeArgs(u256(s1.length()), s1); - bytes args1 = encodeArgs(u256(0x80), u256(3), u256(4), u256(5)) + dyn1; - BOOST_REQUIRE( - callContractFunction("f(bytes,uint256,uint256,uint256)", asString(args1)) == - encodeArgs(string{s1[3]}, string{s1[4]}, string{s1[5]}) - ); -} - -BOOST_AUTO_TEST_CASE(bytes_in_constructors_unpacker) -{ - char const* sourceCode = R"( - contract Test { - uint public m_x; - bytes public m_s; - constructor(uint x, bytes memory s) public { - m_x = x; - m_s = s; - } - } - )"; - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - bytes dyn1 = encodeArgs(u256(s1.length()), s1); - u256 x = 7; - bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; - compileAndRun(sourceCode, 0, "Test", args1); - BOOST_REQUIRE(callContractFunction("m_x()") == encodeArgs(x)); - BOOST_REQUIRE(callContractFunction("m_s()") == encodeArgs(u256(0x20)) + dyn1); -} - -BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer) -{ - char const* sourceCode = R"( - contract Base { - uint public m_x; - bytes m_s; - constructor(uint x, bytes memory s) public { - m_x = x; - m_s = s; - } - function part(uint i) public returns (byte) { - return m_s[i]; - } - } - contract Main is Base { - constructor(bytes memory s, uint x) Base(x, f(s)) public {} - function f(bytes memory s) public returns (bytes memory) { - return s; - } - } - contract Creator { - function f(uint x, bytes memory s) public returns (uint r, byte ch) { - Main c = new Main(s, x); - r = c.m_x(); - ch = c.part(x); - } - } - )"; - compileAndRun(sourceCode, 0, "Creator"); - string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); - bytes dyn1 = encodeArgs(u256(s1.length()), s1); - u256 x = 7; - bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; - BOOST_REQUIRE( - callContractFunction("f(uint256,bytes)", asString(args1)) == - encodeArgs(x, string{s1[unsigned(x)]}) - ); -} - -BOOST_AUTO_TEST_CASE(arrays_in_constructors) -{ - char const* sourceCode = R"( - contract Base { - uint public m_x; - address[] m_s; - constructor(uint x, address[] memory s) public { - m_x = x; - m_s = s; - } - function part(uint i) public returns (address) { - return m_s[i]; - } - } - contract Main is Base { - constructor(address[] memory s, uint x) Base(x, f(s)) public {} - function f(address[] memory s) public returns (address[] memory) { - return s; - } - } - contract Creator { - function f(uint x, address[] memory s) public returns (uint r, address ch) { - Main c = new Main(s, x); - r = c.m_x(); - ch = c.part(x); - } - } - )"; - compileAndRun(sourceCode, 0, "Creator"); - vector s1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - bytes dyn1 = encodeArgs(u256(s1.size()), s1); - u256 x = 7; - bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; - BOOST_REQUIRE( - callContractFunction("f(uint256,address[])", asString(args1)) == - encodeArgs(x, s1[unsigned(x)]) - ); -} - -BOOST_AUTO_TEST_CASE(fixed_arrays_in_constructors) -{ - char const* sourceCode = R"( - contract Creator { - uint public r; - address public ch; - constructor(address[3] memory s, uint x) public { - r = x; - ch = s[2]; - } - } - )"; - compileAndRun(sourceCode, 0, "Creator", encodeArgs(u256(1), u256(2), u256(3), u256(4))); - BOOST_REQUIRE(callContractFunction("r()") == encodeArgs(u256(4))); - BOOST_REQUIRE(callContractFunction("ch()") == encodeArgs(u256(3))); -} - -BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) -{ - char const* sourceCode = R"( - contract Test { - uint24[] public data; - function set(uint24[] memory _data) public returns (uint) { - data = _data; - return data.length; - } - function get() public returns (uint24[] memory) { - return data; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; - BOOST_REQUIRE( - callContractFunction("set(uint24[])", u256(0x20), u256(data.size()), data) == - encodeArgs(u256(data.size())) - ); - ABI_CHECK(callContractFunction("data(uint256)", u256(7)), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("data(uint256)", u256(15)), encodeArgs(u256(16))); - ABI_CHECK(callContractFunction("data(uint256)", u256(18)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size()), data)); -} - -BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) -{ - char const* sourceCode = R"( - contract Test { - uint24[3][] public data; - function set(uint24[3][] memory _data) public returns (uint) { - data = _data; - return data.length; - } - function get() public returns (uint24[3][] memory) { - return data; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; - BOOST_REQUIRE( - callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == - encodeArgs(u256(data.size() / 3)) - ); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)), encodeArgs(u256(9))); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)), encodeArgs(u256(17))); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size() / 3), data)); -} - -BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) -{ - char const* sourceCode = R"( - contract Test { - function set(uint24[3][] memory _data, uint a, uint b) public returns (uint l, uint e) { - l = _data.length; - e = _data[a][b]; - } - } - )"; - vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Test"); - - BOOST_REQUIRE(callContractFunction( - "set(uint24[3][],uint256,uint256)", - u256(0x60), - u256(3), - u256(2), - u256(data.size() / 3), - data - ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); - ); -} - -BOOST_AUTO_TEST_CASE(bytes_memory_index_access) -{ - char const* sourceCode = R"( - contract Test { - function set(bytes memory _data, uint i) public returns (uint l, byte c) { - l = _data.length; - c = _data[i]; - } - } - )"; - string data("abcdefgh"); - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Test"); - - BOOST_REQUIRE(callContractFunction( - "set(bytes,uint256)", - u256(0x40), - u256(3), - u256(data.size()), - data - ) == encodeArgs(u256(data.size()), string("d"))); - ); -} - -BOOST_AUTO_TEST_CASE(storage_array_ref) -{ - char const* sourceCode = R"( - contract BinarySearch { - /// Finds the position of _value in the sorted list _data. - /// Note that "internal" is important here, because storage references only work for internal or private functions - function find(uint[] storage _data, uint _value) internal returns (uint o_position) { - return find(_data, 0, _data.length, _value); - } - function find(uint[] storage _data, uint _begin, uint _len, uint _value) private returns (uint o_position) { - if (_len == 0 || (_len == 1 && _data[_begin] != _value)) - return uint(-1); // failure - uint halfLen = _len / 2; - uint v = _data[_begin + halfLen]; - if (_value < v) - return find(_data, _begin, halfLen, _value); - else if (_value > v) - return find(_data, _begin + halfLen + 1, halfLen - 1, _value); - else - return _begin + halfLen; - } - } - - contract Store is BinarySearch { - uint[] data; - function add(uint v) public { - data.push(0); - data[data.length - 1] = v; - } - function find(uint v) public returns (uint) { - return find(data, v); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Store"); - BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(-1))); - BOOST_REQUIRE(callContractFunction("add(uint256)", u256(7)) == encodeArgs()); - BOOST_REQUIRE(callContractFunction("find(uint256)", u256(7)) == encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("add(uint256)", u256(11)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(17)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(27)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(31)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(32)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(66)), encodeArgs()); - ABI_CHECK(callContractFunction("add(uint256)", u256(177)), encodeArgs()); - ABI_CHECK(callContractFunction("find(uint256)", u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("find(uint256)", u256(27)), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("find(uint256)", u256(32)), encodeArgs(u256(5))); - ABI_CHECK(callContractFunction("find(uint256)", u256(176)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("find(uint256)", u256(0)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("find(uint256)", u256(400)), encodeArgs(u256(-1))); - ); -} - -BOOST_AUTO_TEST_CASE(memory_types_initialisation) -{ - char const* sourceCode = R"( - contract Test { - mapping(uint=>uint) data; - function stat() public returns (uint[5] memory) - { - data[2] = 3; // make sure to use some memory - } - function dyn() public returns (uint[] memory) { stat(); } - function nested() public returns (uint[3][] memory) { stat(); } - function nestedStat() public returns (uint[3][7] memory) { stat(); } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("stat()"), encodeArgs(vector(5))); - ABI_CHECK(callContractFunction("dyn()"), encodeArgs(u256(0x20), u256(0))); - ABI_CHECK(callContractFunction("nested()"), encodeArgs(u256(0x20), u256(0))); - ABI_CHECK(callContractFunction("nestedStat()"), encodeArgs(vector(3 * 7))); -} - -BOOST_AUTO_TEST_CASE(memory_arrays_delete) -{ - char const* sourceCode = R"( - contract Test { - function del() public returns (uint24[3][4] memory) { - uint24[3][4] memory x; - for (uint24 i = 0; i < x.length; i ++) - for (uint24 j = 0; j < x[i].length; j ++) - x[i][j] = i * 0x10 + j; - delete x[1]; - delete x[3][2]; - return x; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data(3 * 4); - for (unsigned i = 0; i < 4; i++) - for (unsigned j = 0; j < 3; j++) - { - u256 v = 0; - if (!(i == 1 || (i == 3 && j == 2))) - v = i * 0x10 + j; - data[i * 3 + j] = v; - } - ABI_CHECK(callContractFunction("del()"), encodeArgs(data)); -} - -BOOST_AUTO_TEST_CASE(memory_arrays_index_access_write) -{ - char const* sourceCode = R"( - contract Test { - function set(uint24[3][4] memory x) public { - x[2][2] = 1; - x[3][2] = 7; - } - function f() public returns (uint24[3][4] memory){ - uint24[3][4] memory data; - set(data); - return data; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data(3 * 4); - data[3 * 2 + 2] = 1; - data[3 * 3 + 2] = 7; - ABI_CHECK(callContractFunction("f()"), encodeArgs(data)); -} - -BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) -{ - char const* sourceCode = R"( - contract Test { - uint24[3][][4] data; - function set(uint24[3][][4] memory x) internal returns (uint24[3][][4] memory) { - x[1][2][2] = 1; - x[1][3][2] = 7; - return x; - } - function f() public returns (uint24[3][] memory) { - while (data[1].length < 4) - data[1].push(); - return set(data)[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data(3 * 4); - data[3 * 2 + 2] = 1; - data[3 * 3 + 2] = 7; - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x20), u256(4), data)); -} - -BOOST_AUTO_TEST_CASE(memory_structs_read_write) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; uint8[2] a; } - S[5] data; - function testInit() public returns (uint8 x, uint16 y, uint z, uint8 a, bool flag) { - S[2] memory d; - x = d[0].x; - y = d[0].y; - z = d[0].z; - a = d[0].a[1]; - flag = true; - } - function testCopyRead() public returns (uint8 x, uint16 y, uint z, uint8 a) { - data[2].x = 1; - data[2].y = 2; - data[2].z = 3; - data[2].a[1] = 4; - S memory s = data[2]; - x = s.x; - y = s.y; - z = s.z; - a = s.a[1]; - } - function testAssign() public returns (uint8 x, uint16 y, uint z, uint8 a) { - S memory s; - s.x = 1; - s.y = 2; - s.z = 3; - s.a[1] = 4; - x = s.x; - y = s.y; - z = s.z; - a = s.a[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("testInit()"), encodeArgs(u256(0), u256(0), u256(0), u256(0), true)); - ABI_CHECK(callContractFunction("testCopyRead()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); - ABI_CHECK(callContractFunction("testAssign()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - -BOOST_AUTO_TEST_CASE(memory_structs_as_function_args) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - function test() public returns (uint x, uint y, uint z) { - S memory data = combine(1, 2, 3); - x = extract(data, 0); - y = extract(data, 1); - z = extract(data, 2); - } - function extract(S memory s, uint which) internal returns (uint x) { - if (which == 0) return s.x; - else if (which == 1) return s.y; - else return s.z; - } - function combine(uint8 x, uint16 y, uint z) internal returns (S memory s) { - s.x = x; - s.y = y; - s.z = z; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(1), u256(2), u256(3))); -} - -BOOST_AUTO_TEST_CASE(memory_structs_nested) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - struct X { uint8 x; S s; } - function test() public returns (uint a, uint x, uint y, uint z) { - X memory d = combine(1, 2, 3, 4); - a = extract(d, 0); - x = extract(d, 1); - y = extract(d, 2); - z = extract(d, 3); - } - function extract(X memory s, uint which) internal returns (uint x) { - if (which == 0) return s.x; - else if (which == 1) return s.s.x; - else if (which == 2) return s.s.y; - else return s.s.z; - } - function combine(uint8 a, uint8 x, uint16 y, uint z) internal returns (X memory s) { - s.x = a; - s.s.x = x; - s.s.y = y; - s.s.z = z; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - -BOOST_AUTO_TEST_CASE(memory_structs_nested_load) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - struct X { uint8 x; S s; uint8[2] a; } - X m_x; - function load() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { - m_x.x = 1; - m_x.s.x = 2; - m_x.s.y = 3; - m_x.s.z = 4; - m_x.a[0] = 5; - m_x.a[1] = 6; - X memory d = m_x; - a = d.x; - x = d.s.x; - y = d.s.y; - z = d.s.z; - a1 = d.a[0]; - a2 = d.a[1]; - } - function store() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { - X memory d; - d.x = 1; - d.s.x = 2; - d.s.y = 3; - d.s.z = 4; - d.a[0] = 5; - d.a[1] = 6; - m_x = d; - a = m_x.x; - x = m_x.s.x; - y = m_x.s.y; - z = m_x.s.z; - a1 = m_x.a[0]; - a2 = m_x.a[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - auto out = encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5), u256(6)); - ABI_CHECK(callContractFunction("load()"), out); - ABI_CHECK(callContractFunction("store()"), out); -} - -BOOST_AUTO_TEST_CASE(struct_constructor_nested) -{ - char const* sourceCode = R"( - contract C { - struct X { uint x1; uint x2; } - struct S { uint s1; uint[3] s2; X s3; } - S s; - constructor() public { - uint[3] memory s2; - s2[1] = 9; - s = S(1, s2, X(4, 5)); - } - function get() public returns (uint s1, uint[3] memory s2, uint x1, uint x2) - { - s1 = s.s1; - s2 = s.s2; - x1 = s.s3.x1; - x2 = s.s3.x2; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - auto out = encodeArgs(u256(1), u256(0), u256(9), u256(0), u256(4), u256(5)); - ABI_CHECK(callContractFunction("get()"), out); -} - -BOOST_AUTO_TEST_CASE(struct_named_constructor) -{ - char const* sourceCode = R"( - contract C { - struct S { uint a; bool x; } - S public s; - constructor() public { - s = S({a: 1, x: true}); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("s()"), encodeArgs(u256(1), true)); -} - -BOOST_AUTO_TEST_CASE(calldata_array) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint[2] calldata s) external pure returns (uint256 a, uint256 b) { - a = s[0]; - b = s[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f(uint256[2])", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S calldata s) external pure returns (uint256 a, uint256 b) { - a = s.a; - b = s.b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256))", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_and_ints) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(uint256 a, S calldata s, uint256 b) external pure returns (uint256, uint256, uint256, uint256) { - return (a, s.a, s.b, b); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f(uint256,(uint256,uint256),uint256)", encodeArgs(u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(1), u256(2), u256(3), u256(4))); -} - - -BOOST_AUTO_TEST_CASE(calldata_structs) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; } - function f(S1 calldata s1, S2 calldata s2, S1 calldata s3) - external pure returns (uint256 a, uint256 b, uint256 c, uint256 d, uint256 e) { - a = s1.a; - b = s1.b; - c = s2.a; - d = s3.a; - e = s3.b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256),(uint256),(uint256,uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_array_member) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256[2] b; uint256 c; } - function f(S calldata s) external pure returns (uint256 a, uint256 b0, uint256 b1, uint256 c) { - a = s.a; - b0 = s.b[0]; - b1 = s.b[1]; - c = s.c; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256[2],uint256))", encodeArgs(u256(42), u256(1), u256(2), u256(23))), encodeArgs(u256(42), u256(1), u256(2), u256(23))); -} - -BOOST_AUTO_TEST_CASE(calldata_array_of_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S[] calldata s) external pure returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) { - l = s.length; - a = s[0].a; - b = s[0].b; - c = s[1].a; - d = s[1].b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256)[])", encodeArgs(u256(0x20), u256(2), u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(2), u256(1), u256(2), u256(3), u256(4))); -} - -BOOST_AUTO_TEST_CASE(calldata_array_of_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S[] calldata s) external pure returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) { - S[] memory m = s; - l = m.length; - a = m[0].a; - b = m[0].b; - c = m[1].a; - d = m[1].b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256)[])", encodeArgs(u256(0x20), u256(2), u256(1), u256(2), u256(3), u256(4))), encodeArgs(u256(2), u256(1), u256(2), u256(3), u256(4))); -} - - -BOOST_AUTO_TEST_CASE(calldata_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S calldata s) external pure returns (uint256, uint256) { - S memory m = s; - return (m.a, m.b); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256))", encodeArgs(u256(42), u256(23))), encodeArgs(u256(42), u256(23))); -} - -BOOST_AUTO_TEST_CASE(nested_calldata_struct) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; uint256 b; S1 s; uint256 c; } - function f(S2 calldata s) external pure returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) { - return (s.a, s.b, s.s.a, s.s.b, s.c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256,(uint256,uint256),uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - -BOOST_AUTO_TEST_CASE(nested_calldata_struct_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S1 { uint256 a; uint256 b; } - struct S2 { uint256 a; uint256 b; S1 s; uint256 c; } - function f(S2 calldata s) external pure returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) { - S2 memory m = s; - return (m.a, m.b, m.s.a, m.s.b, m.c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK(callContractFunction("f((uint256,uint256,(uint256,uint256),uint256))", encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))), encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5))); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_short) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint256 a; uint256 b; } - function f(S calldata) external pure returns (uint256) { - return msg.data.length; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // double check that the valid case goes through - ABI_CHECK(callContractFunction("f((uint256,uint256))", u256(1), u256(2)), encodeArgs(0x44)); - - ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(63,0)), encodeArgs()); - ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(33,0)), encodeArgs()); - ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(32,0)), encodeArgs()); - ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(31,0)), encodeArgs()); - ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes()), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_cleaning) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint8 a; bytes1 b; } - function f(S calldata s) external pure returns (uint256 a, bytes32 b) { - uint8 tmp1 = s.a; - bytes1 tmp2 = s.b; - assembly { - a := tmp1 - b := tmp2 - } - - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // double check that the valid case goes through - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x12), bytes{0x34} + bytes(31,0)), encodeArgs(0x12, bytes{0x34} + bytes(31,0))); - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x1234), bytes{0x56, 0x78} + bytes(30,0)), encodeArgs()); - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(-1), u256(-1)), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calldata_struct_function_type) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { function (uint) external returns (uint) fn; } - function f(S calldata s) external returns (uint256) { - return s.fn(42); - } - function g(uint256 a) external returns (uint256) { - return a * 3; - } - function h(uint256 a) external returns (uint256) { - return 23; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - bytes fn_C_g = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + bytes(8,0); - bytes fn_C_h = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("h(uint256)")).asBytes() + bytes(8,0); - ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_g), encodeArgs(42 * 3)); - ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_h), encodeArgs(23)); -} - -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_bytes) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f1(bytes[1] calldata a) external returns (uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2])); - } - function f2(bytes[1] calldata a, bytes[1] calldata b) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), b[0].length, uint8(b[0][0]), uint8(b[0][1])); - } - function g1(bytes[2] calldata a) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])); - } - function g2(bytes[] calldata a) external returns (uint256[8] memory) { - return [a.length, a[0].length, uint8(a[0][0]), uint8(a[0][1]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])]; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - bytes bytes010203 = bytes{1,2,3}+bytes(29,0); - bytes bytes040506 = bytes{4,5,6}+bytes(29,0); - bytes bytes0102 = bytes{1,2}+bytes(30,0); - ABI_CHECK( - callContractFunction("f1(bytes[1])", 0x20, 0x20, 3, bytes010203), - encodeArgs(3, 1, 2, 3) - ); - ABI_CHECK( - callContractFunction("f2(bytes[1],bytes[1])", 0x40, 0xA0, 0x20, 3, bytes010203, 0x20, 2, bytes0102), - encodeArgs(3, 1, 2, 3, 2, 1, 2) - ); - ABI_CHECK( - callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x80, 3, bytes010203, 3, bytes040506), - encodeArgs(3, 1, 2, 3, 3, 4, 5, 6) - ); - // same offset for both arrays - ABI_CHECK( - callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x40, 3, bytes010203), - encodeArgs(3, 1, 2, 3, 3, 1, 2, 3) - ); - ABI_CHECK( - callContractFunction("g2(bytes[])", 0x20, 2, 0x40, 0x80, 2, bytes0102, 3, bytes040506), - encodeArgs(2, 2, 1, 2, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_dynamic_array_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][] calldata a) external returns (uint, uint256[] memory) { - uint256[] memory m = a[0]; - return (a.length, m); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(uint256[][])", 0x20, 1, 0x20, 2, 23, 42), - encodeArgs(1, 0x40, 2, 23, 42) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_bytes_array_to_memory) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes[] calldata a) external returns (uint, uint, bytes memory) { - bytes memory m = a[0]; - return (a.length, m.length, m); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs(1, 2, 0x60, 2, bytes{'a','b'} + bytes(30, 0)) - ); - - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, bytes(32, 'x')), - encodeArgs(1, 32, 0x60, 32, bytes(32, 'x')) - ); - bytes x_zero_a = bytes{'x'} + bytes(30, 0) + bytes{'a'}; - bytes a_zero_x = bytes{'a'} + bytes(30, 0) + bytes{'x'}; - bytes a_m_x = bytes{'a'} + bytes(30, 'm') + bytes{'x'}; - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, x_zero_a), - encodeArgs(1, 32, 0x60, 32, x_zero_a) - ); - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_zero_x), - encodeArgs(1, 32, 0x60, 32, a_zero_x) - ); - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_m_x), - encodeArgs(1, 32, 0x60, 32, a_m_x) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes[] calldata a, uint256 i) external returns (uint) { - return uint8(a[0][i]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 0, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs('a') - ); - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 1, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs('b') - ); - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs() - ); -} - -BOOST_AUTO_TEST_CASE(calldata_string_array) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(string[] calldata a) external returns (uint, uint, uint, string memory) { - string memory s1 = a[0]; - bytes memory m1 = bytes(s1); - return (a.length, m1.length, uint8(m1[0]), s1); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(string[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs(1, 2, 'a', 0x80, 2, bytes{'a', 'b'} + bytes(30, 0)) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) -{ - vector> data { - { 0x0A01, 0x0A02, 0x0A03 }, - { 0x0B01, 0x0B02, 0x0B03, 0x0B04 } - }; - - for (bool outerDynamicallySized: { true, false }) - { - string arrayType = outerDynamicallySized ? "uint256[][]" : "uint256[][2]"; - string sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function test()" + arrayType + R"( calldata a) external returns (uint256) { - return a.length; - } - function test()" + arrayType + R"( calldata a, uint256 i) external returns (uint256) { - return a[i].length; - } - function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { - return a[i][j]; - } - function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { - return this.test(a, i, j); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - bytes encoding = encodeArray( - outerDynamicallySized, - true, - data | boost::adaptors::transformed([&](vector const& _values) { - return encodeArray(true, false, _values); - }) - ); - - ABI_CHECK(callContractFunction("test(" + arrayType + ")", 0x20, encoding), encodeArgs(data.size())); - for (size_t i = 0; i < data.size(); i++) - { - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size())); - for (size_t j = 0; j < data[i].size(); j++) - { - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); - ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); - } - // out of bounds access - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs()); - } - // out of bounds access - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs()); - } -} - -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) -{ - vector>> data { - { - { 0x010A01, 0x010A02, 0x010A03 }, - { 0x010B01, 0x010B02, 0x010B03 } - }, - { - { 0x020A01, 0x020A02, 0x020A03 }, - { 0x020B01, 0x020B02, 0x020B03 } - } - }; - - for (bool outerDynamicallySized: { true, false }) - for (bool middleDynamicallySized: { true, false }) - for (bool innerDynamicallySized: { true, false }) - { - // only test dynamically encoded arrays - if (!outerDynamicallySized && !middleDynamicallySized && !innerDynamicallySized) - continue; - - string arrayType = "uint256"; - arrayType += innerDynamicallySized ? "[]" : "[3]"; - arrayType += middleDynamicallySized ? "[]" : "[2]"; - arrayType += outerDynamicallySized ? "[]" : "[2]"; - - string sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function test()" + arrayType + R"( calldata a) external returns (uint256) { - return a.length; - } - function test()" + arrayType + R"( calldata a, uint256 i) external returns (uint256) { - return a[i].length; - } - function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { - return a[i][j].length; - } - function test()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { - return a[i][j][k]; - } - function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { - return this.test(a, i, j, k); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - bytes encoding = encodeArray( - outerDynamicallySized, - middleDynamicallySized || innerDynamicallySized, - data | boost::adaptors::transformed([&](auto const& _middleData) { - return encodeArray( - middleDynamicallySized, - innerDynamicallySized, - _middleData | boost::adaptors::transformed([&](auto const& _values) { - return encodeArray(innerDynamicallySized, false, _values); - }) - ); - }) - ); - - ABI_CHECK(callContractFunction("test(" + arrayType + ")", 0x20, encoding), encodeArgs(data.size())); - for (size_t i = 0; i < data.size(); i++) - { - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size())); - for (size_t j = 0; j < data[i].size(); j++) - { - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j].size())); - for (size_t k = 0; k < data[i][j].size(); k++) - { - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); - ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); - } - // out of bounds access - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), encodeArgs()); - } - // out of bounds access - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs()); - } - // out of bounds access - ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs()); - } -} - -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_invalid) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][] calldata a) external returns (uint) { - return 42; - } - function g(uint256[][] calldata a) external returns (uint) { - a[0]; - return 42; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // valid access stub - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 0), encodeArgs(42)); - // invalid on argument decoding - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1), encodeArgs()); - // invalid on outer access - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][])", 0x20, 1, 0x20), encodeArgs()); - // invalid on inner access - ABI_CHECK(callContractFunction("f(uint256[][])", 0x20, 1, 0x20, 2, 0x42), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][])", 0x20, 1, 0x20, 2, 0x42), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_invalid_static_middle) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(uint256[][1][] calldata a) external returns (uint) { - return 42; - } - function g(uint256[][1][] calldata a) external returns (uint) { - a[0]; - return 42; - } - function h(uint256[][1][] calldata a) external returns (uint) { - a[0][0]; - return 42; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // valid access stub - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 0), encodeArgs(42)); - // invalid on argument decoding - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1), encodeArgs()); - // invalid on outer access - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20), encodeArgs()); - // invalid on inner access - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs(42)); - ABI_CHECK(callContractFunction("h(uint256[][1][])", 0x20, 1, 0x20, 0x20), encodeArgs()); - ABI_CHECK(callContractFunction("f(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs(42)); - ABI_CHECK(callContractFunction("g(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs(42)); - ABI_CHECK(callContractFunction("h(uint256[][1][])", 0x20, 1, 0x20, 0x20, 1), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(literal_strings) -{ - char const* sourceCode = R"( - contract Test { - string public long; - string public medium; - string public short; - string public empty; - function f() public returns (string memory) { - long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; - medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; - short = "123"; - empty = ""; - return "Hello, World!"; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; - string medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; - string shortStr = "123"; - string hello = "Hello, World!"; - - ABI_CHECK(callContractFunction("f()"), encodeDyn(hello)); - ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr)); - ABI_CHECK(callContractFunction("medium()"), encodeDyn(medium)); - ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); - ABI_CHECK(callContractFunction("empty()"), encodeDyn(string())); -} - -BOOST_AUTO_TEST_CASE(initialise_string_constant) -{ - char const* sourceCode = R"( - contract Test { - string public short = "abcdef"; - string public long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; - } - )"; - compileAndRun(sourceCode, 0, "Test"); - string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; - string shortStr = "abcdef"; - - ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr)); - ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); -} - -BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 a; mapping(uint => uint) b; uint8 c; } - S s; - function f() public returns (uint) { - S memory x; - if (x.a != 0 || x.c != 0) return 1; - x.a = 4; x.c = 5; - s = x; - if (s.a != 4 || s.c != 5) return 2; - x = S(2, 3); - if (x.a != 2 || x.c != 3) return 3; - x = s; - if (s.a != 4 || s.c != 5) return 4; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(string_bytes_conversion) -{ - char const* sourceCode = R"( - contract Test { - string s; - bytes b; - function f(string memory _s, uint n) public returns (byte) { - b = bytes(_s); - s = string(b); - return bytes(s)[n]; - } - function l() public returns (uint) { return bytes(s).length; } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction( - "f(string,uint256)", - u256(0x40), - u256(2), - u256(6), - string("abcdef") - ), encodeArgs("c")); - ABI_CHECK(callContractFunction("l()"), encodeArgs(u256(6))); -} - -BOOST_AUTO_TEST_CASE(string_as_mapping_key) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => uint) data; - function set(string memory _s, uint _v) public { data[_s] = _v; } - function get(string memory _s) public returns (uint) { return data[_s]; } - } - )"; - - vector strings{ - "Hello, World!", - "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", - "", - "1" - }; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Test"); - for (unsigned i = 0; i < strings.size(); i++) - ABI_CHECK(callContractFunction( - "set(string,uint256)", - u256(0x40), - u256(7 + i), - u256(strings[i].size()), - strings[i] - ), encodeArgs()); - for (unsigned i = 0; i < strings.size(); i++) - ABI_CHECK(callContractFunction( - "get(string)", - u256(0x20), - u256(strings[i].size()), - strings[i] - ), encodeArgs(u256(7 + i))); - ) -} - -BOOST_AUTO_TEST_CASE(string_as_public_mapping_key) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => uint) public data; - function set(string memory _s, uint _v) public { data[_s] = _v; } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - vector strings{ - "Hello, World!", - "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", - "", - "1" - }; - for (unsigned i = 0; i < strings.size(); i++) - ABI_CHECK(callContractFunction( - "set(string,uint256)", - u256(0x40), - u256(7 + i), - u256(strings[i].size()), - strings[i] - ), encodeArgs()); - for (unsigned i = 0; i < strings.size(); i++) - ABI_CHECK(callContractFunction( - "data(string)", - u256(0x20), - u256(strings[i].size()), - strings[i] - ), encodeArgs(u256(7 + i))); -} - -BOOST_AUTO_TEST_CASE(nested_string_as_public_mapping_key) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => mapping(string => uint)) public data; - function set(string memory _s, string memory _s2, uint _v) public { - data[_s][_s2] = _v; } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - vector strings{ - "Hello, World!", - "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", - "", - "1", - "last one" - }; - for (unsigned i = 0; i + 1 < strings.size(); i++) - ABI_CHECK(callContractFunction( - "set(string,string,uint256)", - u256(0x60), - u256(roundTo32(0x80 + strings[i].size())), - u256(7 + i), - u256(strings[i].size()), - strings[i], - u256(strings[i+1].size()), - strings[i+1] - ), encodeArgs()); - for (unsigned i = 0; i + 1 < strings.size(); i++) - ABI_CHECK(callContractFunction( - "data(string,string)", - u256(0x40), - u256(roundTo32(0x60 + strings[i].size())), - u256(strings[i].size()), - strings[i], - u256(strings[i+1].size()), - strings[i+1] - ), encodeArgs(u256(7 + i))); -} - -BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => - mapping(int => - mapping(address => - mapping(bytes => int)))) public data; - - function set( - string memory _s1, - int _s2, - address _s3, - bytes memory _s4, - int _value - ) public - { - data[_s1][_s2][_s3][_s4] = _value; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - struct Index - { - string s1; - int s2; - int s3; - string s4; - }; - - vector data{ - { "aabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcbc", 4, 23, "efg" }, - { "tiaron", 456, 63245, "908apzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapz" }, - { "", 2345, 12934, "665i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i5iart" }, - { "¡¿…", 9781, 8148, "" }, - { "ρν♀♀ω₂₃♀", 929608, 303030, "" } - }; - - for (size_t i = 0; i + 1 < data.size(); i++) - ABI_CHECK(callContractFunction( - "set(string,int256,address,bytes,int256)", - u256(0xA0), - u256(data[i].s2), - u256(data[i].s3), - u256(roundTo32(0xC0 + data[i].s1.size())), - u256(i - 3), - u256(data[i].s1.size()), - data[i].s1, - u256(data[i].s4.size()), - data[i].s4 - ), encodeArgs()); - for (size_t i = 0; i + 1 < data.size(); i++) - ABI_CHECK(callContractFunction( - "data(string,int256,address,bytes)", - u256(0x80), - u256(data[i].s2), - u256(data[i].s3), - u256(roundTo32(0xA0 + data[i].s1.size())), - u256(data[i].s1.size()), - data[i].s1, - u256(data[i].s4.size()), - data[i].s4 - ), encodeArgs(u256(i - 3))); -} - -BOOST_AUTO_TEST_CASE(accessor_for_state_variable) -{ - char const* sourceCode = R"( - contract Lotto { - uint public ticketPrice = 500; - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(500))); - ); -} - -BOOST_AUTO_TEST_CASE(accessor_for_const_state_variable) -{ - char const* sourceCode = R"( - contract Lotto{ - uint constant public ticketPrice = 555; - } - )"; - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("ticketPrice()"), encodeArgs(u256(555))); -} - -BOOST_AUTO_TEST_CASE(state_variable_under_contract_name) -{ - char const* text = R"( - contract Scope { - uint stateVar = 42; - - function getStateVar() public view returns (uint stateVar) { - stateVar = Scope.stateVar; - } - } - )"; - compileAndRun(text); - ABI_CHECK(callContractFunction("getStateVar()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(state_variable_local_variable_mixture) -{ - char const* sourceCode = R"( - contract A { - uint x = 1; - uint y = 2; - function a() public returns (uint x) { - x = A.y; - } - } - )"; - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(inherited_function) { - char const* sourceCode = R"( - contract A { function f() virtual internal returns (uint) { return 1; } } - contract B is A { - function f() internal override returns (uint) { return 2; } - function g() public returns (uint) { - return A.f(); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory) { - char const* sourceCode = R"( - contract A { function f(uint[] calldata a) virtual external returns (uint) { return a[0]; } } - contract B is A { - function f(uint[] memory a) public override returns (uint) { return a[1]; } - function g() public returns (uint) { - uint[] memory m = new uint[](2); - m[0] = 42; - m[1] = 23; - return A(this).f(m); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(23))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_memory_interface) { - char const* sourceCode = R"( - interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] memory a) public override returns (uint) { return 42; } } - contract B { - function f(uint[] memory a) public returns (uint) { return a[1]; } - function g() public returns (uint) { - I i = I(new A()); - return i.f(new uint[](2)); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_calldata_calldata_interface) { - char const* sourceCode = R"( - interface I { function f(uint[] calldata a) external returns (uint); } - contract A is I { function f(uint[] calldata a) external override returns (uint) { return 42; } } - contract B { - function f(uint[] memory a) public returns (uint) { return a[1]; } - function g() public returns (uint) { - I i = I(new A()); - return i.f(new uint[](2)); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(inherited_function_from_a_library) { - char const* sourceCode = R"( - library A { function f() internal returns (uint) { return 1; } } - contract B { - function f() internal returns (uint) { return 2; } - function g() public returns (uint) { - return A.f(); - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(inherited_constant_state_var) -{ - char const* sourceCode = R"( - contract A { - uint constant x = 7; - } - contract B is A { - function f() public returns (uint) { - return A.x; - } - } - )"; - - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(constant_string_literal) -{ - char const* sourceCode = R"( - contract Test { - bytes32 constant public b = "abcdefghijklmnopq"; - string constant public x = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca"; - - constructor() public { - string memory xx = x; - bytes32 bb = b; - } - function getB() public returns (bytes32) { return b; } - function getX() public returns (string memory) { return x; } - function getX2() public returns (string memory r) { r = x; } - function unused() public returns (uint) { - "unusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunused"; - return 2; - } - } - )"; - - compileAndRun(sourceCode); - string longStr = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca"; - string shortStr = "abcdefghijklmnopq"; - ABI_CHECK(callContractFunction("b()"), encodeArgs(shortStr)); - ABI_CHECK(callContractFunction("x()"), encodeDyn(longStr)); - ABI_CHECK(callContractFunction("getB()"), encodeArgs(shortStr)); - ABI_CHECK(callContractFunction("getX()"), encodeDyn(longStr)); - ABI_CHECK(callContractFunction("getX2()"), encodeDyn(longStr)); - ABI_CHECK(callContractFunction("unused()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(storage_string_as_mapping_key_without_variable) -{ - char const* sourceCode = R"( - contract Test { - mapping(string => uint) data; - function f() public returns (uint) { - data["abc"] = 2; - return data["abc"]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(library_call) -{ - char const* sourceCode = R"( - library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } - contract Test { - function f(uint x) public returns (uint) { - return Lib.m(x, 9); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(33) * 9)); -} - -BOOST_AUTO_TEST_CASE(library_function_external) -{ - char const* sourceCode = R"( - library Lib { function m(bytes calldata b) external pure returns (byte) { return b[2]; } } - contract Test { - function f(bytes memory b) public pure returns (byte) { - return Lib.m(b); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), "abcde"), encodeArgs("c")); -} - -BOOST_AUTO_TEST_CASE(library_stray_values) -{ - char const* sourceCode = R"( - library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } - contract Test { - function f(uint x) public returns (uint) { - Lib; - Lib.m; - return x + 9; - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(42))); -} - -BOOST_AUTO_TEST_CASE(cross_contract_types) -{ - char const* sourceCode = R"( - contract Lib { struct S {uint a; uint b; } } - contract Test { - function f() public returns (uint r) { - Lib.S memory x = Lib.S({a: 2, b: 3}); - r = x.b; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); -} - -BOOST_AUTO_TEST_CASE(simple_throw) -{ - char const* sourceCode = R"( - contract Test { - function f(uint x) public returns (uint) { - if (x > 10) - return x + 10; - else - revert(); - return 2; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(11)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(strings_in_struct) -{ - char const* sourceCode = R"( - contract buggystruct { - Buggy public bug; - - struct Buggy { - uint first; - uint second; - uint third; - string last; - } - - constructor() public { - bug = Buggy(10, 20, 30, "asdfghjkl"); - } - function getFirst() public returns (uint) - { - return bug.first; - } - function getSecond() public returns (uint) - { - return bug.second; - } - function getThird() public returns (uint) - { - return bug.third; - } - function getLast() public returns (string memory) - { - return bug.last; - } - } - )"; - compileAndRun(sourceCode); - string s = "asdfghjkl"; - ABI_CHECK(callContractFunction("getFirst()"), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("getSecond()"), encodeArgs(u256(20))); - ABI_CHECK(callContractFunction("getThird()"), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("getLast()"), encodeDyn(s)); -} - -BOOST_AUTO_TEST_CASE(fixed_arrays_as_return_type) -{ - char const* sourceCode = R"( - contract A { - function f(uint16 input) public pure returns (uint16[5] memory arr) - { - arr[0] = input; - arr[1] = ++input; - arr[2] = ++input; - arr[3] = ++input; - arr[4] = ++input; - } - } - contract B { - function f() public returns (uint16[5] memory res, uint16[5] memory res2) - { - A a = new A(); - res = a.f(2); - res2 = a.f(1000); - } - } - )"; - compileAndRun(sourceCode, 0, "B"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - u256(2), u256(3), u256(4), u256(5), u256(6), // first return argument - u256(1000), u256(1001), u256(1002), u256(1003), u256(1004)) // second return argument - ); -} - -BOOST_AUTO_TEST_CASE(internal_types_in_library) -{ - char const* sourceCode = R"( - library Lib { - function find(uint16[] storage _haystack, uint16 _needle) public view returns (uint) - { - for (uint i = 0; i < _haystack.length; ++i) - if (_haystack[i] == _needle) - return i; - return uint(-1); - } - } - contract Test { - mapping(string => uint16[]) data; - function f() public returns (uint a, uint b) - { - while (data["abc"].length < 20) - data["abc"].push(); - data["abc"][4] = 9; - data["abc"][17] = 3; - a = Lib.find(data["abc"], 9); - b = Lib.find(data["abc"], 3); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4), u256(17))); -} - -BOOST_AUTO_TEST_CASE(mapping_arguments_in_library) -{ - char const* sourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) internal - { - m[key] = value; - } - function get(mapping(uint => uint) storage m, uint key) internal view returns (uint) - { - return m[key]; - } - } - contract Test { - mapping(uint => uint) m; - function set(uint256 key, uint256 value) public returns (uint) - { - uint oldValue = Lib.get(m, key); - Lib.set(m, key, value); - return oldValue; - } - function get(uint256 key) public view returns (uint) { - return Lib.get(m, key); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(42)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(84)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(21)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(42)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(14)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(14))); -} - -BOOST_AUTO_TEST_CASE(mapping_returns_in_library) -{ - char const* sourceCode = R"( - library Lib { - function choose_mapping(mapping(uint => uint) storage a, mapping(uint => uint) storage b, bool c) internal pure returns(mapping(uint=>uint) storage) - { - return c ? a : b; - } - } - contract Test { - mapping(uint => uint) a; - mapping(uint => uint) b; - function set(bool choice, uint256 key, uint256 value) public returns (uint) - { - mapping(uint => uint) storage m = Lib.choose_mapping(a, b, choice); - uint oldValue = m[key]; - m[key] = value; - return oldValue; - } - function get(bool choice, uint256 key) public view returns (uint) { - return Lib.choose_mapping(a, b, choice)[key]; - } - function get_a(uint256 key) public view returns (uint) { - return a[key]; - } - function get_b(uint256 key) public view returns (uint) { - return b[key]; - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(42)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(84)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(7)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(10)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(11)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(12)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(21)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(42)), encodeArgs(u256(84))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(14)), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(30)), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(31)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(32)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(14))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(21))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(14))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(31))); - ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(32))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(31))); - ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(32))); -} - -BOOST_AUTO_TEST_CASE(mapping_returns_in_library_named) -{ - char const* sourceCode = R"( - library Lib { - function f(mapping(uint => uint) storage a, mapping(uint => uint) storage b) internal returns(mapping(uint=>uint) storage r) - { - r = a; - r[1] = 42; - r = b; - r[1] = 21; - } - } - contract Test { - mapping(uint => uint) a; - mapping(uint => uint) b; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.f(a, b)[2] = 84; - return (a[0], a[1], a[2], b[0], b[1], b[2]); - } - function g() public returns (uint, uint, uint, uint, uint, uint) - { - mapping(uint => uint) storage m = Lib.f(a, b); - m[2] = 17; - return (a[0], a[1], a[2], b[0], b[1], b[2]); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(84))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(17))); -} - -BOOST_AUTO_TEST_CASE(using_library_mappings_public) -{ - char const* sourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) public - { - m[key] = value; - } - } - contract Test { - mapping(uint => uint) m1; - mapping(uint => uint) m2; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.set(m1, 0, 1); - Lib.set(m1, 2, 42); - Lib.set(m2, 0, 23); - Lib.set(m2, 2, 99); - return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); -} - -BOOST_AUTO_TEST_CASE(using_library_mappings_external) -{ - char const* libSourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) external - { - m[key] = value * 2; - } - } - )"; - char const* sourceCode = R"( - library Lib { - function set(mapping(uint => uint) storage m, uint key, uint value) external {} - } - contract Test { - mapping(uint => uint) m1; - mapping(uint => uint) m2; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.set(m1, 0, 1); - Lib.set(m1, 2, 42); - Lib.set(m2, 0, 23); - Lib.set(m2, 2, 99); - return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); - } - } - )"; - for (auto v2: {false, true}) - { - string prefix = v2 ? "pragma experimental ABIEncoderV2;\n" : ""; - compileAndRun(prefix + libSourceCode, 0, "Lib"); - compileAndRun(prefix + sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2), u256(0), u256(84), u256(46), u256(0), u256(198))); - } -} - -BOOST_AUTO_TEST_CASE(using_library_mappings_return) -{ - char const* sourceCode = R"( - library Lib { - function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) { - return m[key]; - } - } - contract Test { - mapping(uint => mapping(uint => uint)) m; - function f() public returns (uint, uint, uint, uint, uint, uint) - { - Lib.choose(m, 0)[0] = 1; - Lib.choose(m, 0)[2] = 42; - Lib.choose(m, 1)[0] = 23; - Lib.choose(m, 1)[2] = 99; - return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]); - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); -} - -BOOST_AUTO_TEST_CASE(using_library_structs) -{ - char const* sourceCode = R"( - library Lib { - struct Data { uint a; uint[] b; } - function set(Data storage _s) public - { - _s.a = 7; - while (_s.b.length < 20) - _s.b.push(); - _s.b[19] = 8; - } - } - contract Test { - mapping(string => Lib.Data) data; - function f() public returns (uint a, uint b) - { - Lib.set(data["abc"]); - a = data["abc"].a; - b = data["abc"].b[19]; - } - } - )"; - compileAndRun(sourceCode, 0, "Lib"); - compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), u256(8))); -} - -BOOST_AUTO_TEST_CASE(library_struct_as_an_expression) -{ - char const* sourceCode = R"( - library Arst { - struct Foo { - int Things; - int Stuff; - } - } - - contract Tsra { - function f() public returns(uint) { - Arst.Foo; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "Tsra"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(library_enum_as_an_expression) -{ - char const* sourceCode = R"( - library Arst { - enum Foo { - Things, - Stuff - } - } - - contract Tsra { - function f() public returns(uint) { - Arst.Foo; - return 1; - } - } - )"; - compileAndRun(sourceCode, 0, "Tsra"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(short_strings) -{ - // This test verifies that the byte array encoding that combines length and data works - // correctly. - char const* sourceCode = R"( - contract A { - bytes public data1 = "123"; - bytes data2; - function lengthChange() public returns (uint) - { - // store constant in short and long string - data1 = "123"; - if (!equal(data1, "123")) return 1; - data2 = "12345678901234567890123456789012345678901234567890a"; - if (data2[17] != "8") return 3; - if (data2.length != 51) return 4; - if (data2[data2.length - 1] != "a") return 5; - // change length: short -> short - while (data1.length < 5) - data1.push(); - if (data1.length != 5) return 6; - data1[4] = "4"; - if (data1[0] != "1") return 7; - if (data1[4] != "4") return 8; - // change length: short -> long - while (data1.length < 80) - data1.push(); - if (data1.length != 80) return 9; - while (data1.length > 70) - data1.pop(); - if (data1.length != 70) return 9; - if (data1[0] != "1") return 10; - if (data1[4] != "4") return 11; - for (uint i = 0; i < data1.length; i ++) - data1[i] = byte(uint8(i * 3)); - if (uint8(data1[4]) != 4 * 3) return 12; - if (uint8(data1[67]) != 67 * 3) return 13; - // change length: long -> short - while (data1.length > 22) - data1.pop(); - if (data1.length != 22) return 14; - if (uint8(data1[21]) != 21 * 3) return 15; - if (uint8(data1[2]) != 2 * 3) return 16; - // change length: short -> shorter - while (data1.length > 19) - data1.pop(); - if (data1.length != 19) return 17; - if (uint8(data1[7]) != 7 * 3) return 18; - // and now again to original size - while (data1.length < 22) - data1.push(); - if (data1.length != 22) return 19; - if (data1[21] != 0) return 20; - while (data1.length > 0) - data1.pop(); - while (data2.length > 0) - data2.pop(); - } - function copy() public returns (uint) { - bytes memory x = "123"; - bytes memory y = "012345678901234567890123456789012345678901234567890123456789"; - bytes memory z = "1234567"; - data1 = x; - data2 = y; - if (!equal(data1, x)) return 1; - if (!equal(data2, y)) return 2; - // lengthen - data1 = y; - if (!equal(data1, y)) return 3; - // shorten - data1 = x; - if (!equal(data1, x)) return 4; - // change while keeping short - data1 = z; - if (!equal(data1, z)) return 5; - // copy storage -> storage - data1 = x; - data2 = y; - // lengthen - data1 = data2; - if (!equal(data1, y)) return 6; - // shorten - data1 = x; - data2 = data1; - if (!equal(data2, x)) return 7; - bytes memory c = data2; - data1 = c; - if (!equal(data1, x)) return 8; - data1 = ""; - data2 = ""; - } - function deleteElements() public returns (uint) { - data1 = "01234"; - delete data1[2]; - if (data1[2] != 0) return 1; - if (data1[0] != "0") return 2; - if (data1[3] != "3") return 3; - delete data1; - if (data1.length != 0) return 4; - } - - function equal(bytes storage a, bytes memory b) internal returns (bool) { - if (a.length != b.length) return false; - for (uint i = 0; i < a.length; ++i) if (a[i] != b[i]) return false; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "A"); - ABI_CHECK(callContractFunction("data1()"), encodeDyn(string("123"))); - ABI_CHECK(callContractFunction("lengthChange()"), encodeArgs(u256(0))); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("deleteElements()"), encodeArgs(u256(0))); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("copy()"), encodeArgs(u256(0))); - BOOST_CHECK(storageEmpty(m_contractAddress)); -} - -BOOST_AUTO_TEST_CASE(calldata_offset) -{ - // This tests a specific bug that was caused by not using the correct memory offset in the - // calldata unpacker. - char const* sourceCode = R"( - contract CB - { - address[] _arr; - string public last = "nd"; - constructor(address[] memory guardians) public - { - _arr = guardians; - } - } - )"; - compileAndRun(sourceCode, 0, "CB", encodeArgs(u256(0x20), u256(0x00))); - ABI_CHECK(callContractFunction("last()", encodeArgs()), encodeDyn(string("nd"))); -} - -BOOST_AUTO_TEST_CASE(contract_binary_dependencies) -{ - char const* sourceCode = R"( - contract A { function f() public { new B(); } } - contract B { function f() public { } } - contract C { function f() public { new B(); } } - )"; - compileAndRun(sourceCode); -} - -BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) -{ - char const* sourceCode = R"( - library lib {} - contract c { - constructor() public payable {} - function f(address payable x) public returns (bool) { - return x.send(1); - } - receive () external payable {} - } - )"; - compileAndRun(sourceCode, 0, "lib"); - Address libraryAddress = m_contractAddress; - compileAndRun(sourceCode, 10, "c"); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); - BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); - ABI_CHECK(callContractFunction("f(address)", encodeArgs(u160(libraryAddress))), encodeArgs(false)); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); - BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); - ABI_CHECK(callContractFunction("f(address)", encodeArgs(u160(m_contractAddress))), encodeArgs(true)); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); - BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); -} -BOOST_AUTO_TEST_CASE(multi_variable_declaration) -{ - char const* sourceCode = R"( - contract C { - function g() public returns (uint a, uint b, uint c) { - a = 1; b = 2; c = 3; - } - function h() public returns (uint a, uint b, uint c, uint d) { - a = 1; b = 2; c = 3; d = 4; - } - function f1() public returns (bool) { - (uint x, uint y, uint z) = g(); - if (x != 1 || y != 2 || z != 3) return false; - (, uint a,) = g(); - if (a != 2) return false; - (uint b, , ) = g(); - if (b != 1) return false; - (, , uint c) = g(); - if (c != 3) return false; - return true; - } - function f2() public returns (bool) { - (uint a1, , uint a3, ) = h(); - if (a1 != 1 || a3 != 3) return false; - (uint b1, uint b2, , ) = h(); - if (b1 != 1 || b2 != 2) return false; - (, uint c2, uint c3, ) = h(); - if (c2 != 2 || c3 != 3) return false; - (, , uint d3, uint d4) = h(); - if (d3 != 3 || d4 != 4) return false; - (uint e1, , uint e3, uint e4) = h(); - if (e1 != 1 || e3 != 3 || e4 != 4) return false; - return true; - } - function f() public returns (bool) { - return f1() && f2(); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()", encodeArgs()), encodeArgs(true)); -} + ABI_CHECK(callContractFunction("foo()"), encodeArgs(util::keccak256("foo"))); -BOOST_AUTO_TEST_CASE(typed_multi_variable_declaration) -{ - char const* sourceCode = R"( - contract C { - struct S { uint x; } - S s; - function g() internal returns (uint, S storage, uint) { - s.x = 7; - return (1, s, 2); - } - function f() public returns (bool) { - (uint x1, S storage y1, uint z1) = g(); - if (x1 != 1 || y1.x != 7 || z1 != 2) return false; - (, S storage y2,) = g(); - if (y2.x != 7) return false; - (uint x2,,) = g(); - if (x2 != 1) return false; - (,,uint z2) = g(); - if (z2 != 2) return false; - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()", encodeArgs()), encodeArgs(true)); + ABI_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12), encodeArgs( + util::keccak256( + toBigEndian(u256(10)) + + bytes{0x0, 0xc} + + bytes(1, 0x91) + + bytes{0x66, 0x6f, 0x6f} + ) + )); } -BOOST_AUTO_TEST_CASE(tuples) +BOOST_AUTO_TEST_CASE(iterated_keccak256_with_bytes) { - char const* sourceCode = R"( - contract C { - uint[] data; - uint[] m_c; - function g() internal returns (uint a, uint b, uint[] storage c) { - return (1, 2, data); - } - function h() external returns (uint a, uint b) { - return (5, 6); - } - function f() public returns (uint) { - data.push(3); - uint a; uint b; - (a, b) = this.h(); - if (a != 5 || b != 6) return 1; - uint[] storage c = m_c; - (a, b, c) = g(); - if (a != 1 || b != 2 || c[0] != 3) return 2; - (a, b) = (b, a); - if (a != 2 || b != 1) return 3; - (a, , b, , ) = (8, 9, 10, 11, 12); - if (a != 8 || b != 10) return 4; + char const* sourceCode = R"ABC( + contract c { + bytes data; + function foo() public returns (bytes32) + { + data.push("x"); + data.push("y"); + data.push("z"); + return keccak256(abi.encodePacked("b", keccak256(data), "a")); } } - )"; + )ABC"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("foo()"), encodeArgs( + u256(util::keccak256(bytes{'b'} + util::keccak256("xyz").asBytes() + bytes{'a'})) + )); } -BOOST_AUTO_TEST_CASE(string_tuples) +BOOST_AUTO_TEST_CASE(generic_call) { - char const* sourceCode = R"( - contract C { - function f() public returns (string memory, uint) { - return ("abc", 8); - } - function g() public returns (string memory, string memory) { - return (h(), "def"); - } - function h() public returns (string memory) { - return ("abc"); + char const* sourceCode = R"**( + contract receiver { + uint public received; + function recv(uint256 x) public payable { received = x; } } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x40), u256(8), u256(3), string("abc"))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0x40), u256(0x80), u256(3), string("abc"), u256(3), string("def"))); -} - -BOOST_AUTO_TEST_CASE(decayed_tuple) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint x = 1; - (x) = 2; - return x; + contract sender { + constructor() public payable {} + function doSend(address rec) public returns (uint d) + { + bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)"))); + rec.call.value(2)(abi.encodeWithSelector(signature, 23)); + return receiver(rec).received(); + } } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); + )**"; + compileAndRun(sourceCode, 0, "receiver"); + u160 const c_receiverAddress = m_contractAddress; + compileAndRun(sourceCode, 50, "sender"); + BOOST_REQUIRE(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(23)); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 50 - 2); } -BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers) +BOOST_AUTO_TEST_CASE(generic_delegatecall) { - char const* sourceCode = R"( - contract c { - function f() public returns (int8) { - int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; - return foo3[0]; + char const* sourceCode = R"**( + contract Receiver { + uint public received; + address public sender; + uint public value; + constructor() public payable {} + function recv(uint256 x) public payable { received = x; sender = msg.sender; value = msg.value; } } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(destructuring_assignment) -{ - char const* sourceCode = R"( - contract C { - uint x = 7; - bytes data; - uint[] y; - uint[] arrayData; - function returnsArray() public returns (uint[] memory) { - arrayData = new uint[](9); - arrayData[2] = 5; - arrayData[7] = 4; - return arrayData; - } - function f(bytes memory s) public returns (uint) { - uint loc; - uint[] memory memArray; - (loc, x, y, data, arrayData[3]) = (8, 4, returnsArray(), s, 2); - if (loc != 8) return 1; - if (x != 4) return 2; - if (y.length != 9) return 3; - if (y[2] != 5) return 4; - if (y[7] != 4) return 5; - if (data.length != s.length) return 6; - if (data[3] != s[3]) return 7; - if (arrayData[3] != 2) return 8; - (memArray, loc) = (arrayData, 3); - if (loc != 3) return 9; - if (memArray.length != arrayData.length) return 10; - bytes memory memBytes; - (x, memBytes, y[2], , ) = (456, s, 789, 101112, 131415); - if (x != 456 || memBytes.length != s.length || y[2] != 789) return 11; + contract Sender { + uint public received; + address public sender; + uint public value; + constructor() public payable {} + function doSend(address rec) public payable + { + bytes4 signature = bytes4(bytes32(keccak256("recv(uint256)"))); + (bool success,) = rec.delegatecall(abi.encodeWithSelector(signature, 23)); + success; + } } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), string("abcde")), encodeArgs(u256(0))); -} + )**"; -BOOST_AUTO_TEST_CASE(lone_struct_array_type) -{ - char const* sourceCode = R"( - contract C { - struct s { uint a; uint b;} - function f() public returns (uint) { - s[7][]; // This is only the type, should not have any effect - return 3; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); - ) -} + for (auto v2: {false, true}) + { + string source = (v2 ? "pragma experimental ABIEncoderV2;\n" : "") + string(sourceCode); -BOOST_AUTO_TEST_CASE(create_memory_array) -{ - char const* sourceCode = R"( - contract C { - struct S { uint[2] a; bytes b; } - function f() public returns (byte, uint, uint, byte) { - bytes memory x = new bytes(200); - x[199] = 'A'; - uint[2][] memory y = new uint[2][](300); - y[203][1] = 8; - S[] memory z = new S[](180); - z[170].a[1] = 4; - z[170].b = new bytes(102); - z[170].b[99] = 'B'; - return (x[199], y[203][1], z[170].a[1], z[170].b[99]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(string("A"), u256(8), u256(4), string("B"))); + compileAndRun(source, 0, "Receiver"); + u160 const c_receiverAddress = m_contractAddress; + compileAndRun(source, 50, "Sender"); + u160 const c_senderAddress = m_contractAddress; + BOOST_CHECK(m_sender != c_senderAddress); // just for sanity + ABI_CHECK(callContractFunctionWithValue("doSend(address)", 11, c_receiverAddress), encodeArgs()); + ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(23))); + ABI_CHECK(callContractFunction("sender()"), encodeArgs(u160(m_sender))); + ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(11))); + m_contractAddress = c_receiverAddress; + ABI_CHECK(callContractFunction("received()"), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("sender()"), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("value()"), encodeArgs(u256(0))); + BOOST_CHECK(storageEmpty(c_receiverAddress)); + BOOST_CHECK(!storageEmpty(c_senderAddress)); + BOOST_CHECK_EQUAL(balanceAt(c_receiverAddress), 0); + BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50 + 11); + } } -BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) +BOOST_AUTO_TEST_CASE(generic_staticcall) { - // Check allocation size of byte array. Should be 32 plus length rounded up to next - // multiple of 32 - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint d1, uint d2, uint d3, uint memsize) { - bytes memory b1 = new bytes(31); - bytes memory b2 = new bytes(32); - bytes memory b3 = new bytes(256); - bytes memory b4 = new bytes(31); - assembly { - d1 := sub(b2, b1) - d2 := sub(b3, b2) - d3 := sub(b4, b3) - memsize := msize() - } - } - } - )"; - if (!m_optimiserSettings.runYulOptimiser) + if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall()) { - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256, 0x260)); + char const* sourceCode = R"**( + contract A { + uint public x; + constructor() public { x = 42; } + function pureFunction(uint256 p) public pure returns (uint256) { return p; } + function viewFunction(uint256 p) public view returns (uint256) { return p + x; } + function nonpayableFunction(uint256 p) public returns (uint256) { x = p; return x; } + function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; } + } + contract C { + function f(address a) public view returns (bool, bytes memory) + { + return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23)); + } + function g(address a) public view returns (bool, bytes memory) + { + return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23)); + } + function h(address a) public view returns (bool, bytes memory) + { + return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23)); + } + function i(address a, uint256 v) public view returns (bool, bytes memory) + { + return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v)); + } + } + )**"; + compileAndRun(sourceCode, 0, "A"); + u160 const c_addressA = m_contractAddress; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23)); + ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42)); + ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00)); + ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42)); + ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x00)); } } -BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes) +BOOST_AUTO_TEST_CASE(library_call_in_homestead) { - // Computes binomial coefficients the chinese way char const* sourceCode = R"( - contract C { - function f(uint n, uint k) public returns (uint) { - uint[][] memory rows = new uint[][](n + 1); - for (uint i = 1; i <= n; i++) { - rows[i] = new uint[](i); - rows[i][0] = rows[i][rows[i].length - 1] = 1; - for (uint j = 1; j < i - 1; j++) - rows[i][j] = rows[i - 1][j - 1] + rows[i - 1][j]; - } - return rows[n][k - 1]; + library Lib { function m() public returns (address) { return msg.sender; } } + contract Test { + address public sender; + function f() public { + sender = Lib.m(); } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(3), u256(1))), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(9), u256(5))), encodeArgs(u256(70))); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs()); + ABI_CHECK(callContractFunction("sender()"), encodeArgs(u160(m_sender))); } -BOOST_AUTO_TEST_CASE(create_multiple_dynamic_arrays) +BOOST_AUTO_TEST_CASE(library_call_protection) { + // This tests code that reverts a call if it is a direct call to a library + // as opposed to a delegatecall. char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint[][] memory x = new uint[][](42); - assert(x[0].length == 0); - x[0] = new uint[](1); - x[0][0] = 1; - assert(x[4].length == 0); - x[4] = new uint[](1); - x[4][0] = 2; - assert(x[10].length == 0); - x[10] = new uint[](1); - x[10][0] = 44; - uint[][] memory y = new uint[][](24); - assert(y[0].length == 0); - y[0] = new uint[](1); - y[0][0] = 1; - assert(y[4].length == 0); - y[4] = new uint[](1); - y[4][0] = 2; - assert(y[10].length == 0); - y[10] = new uint[](1); - y[10][0] = 88; - if ((x[0][0] == y[0][0]) && (x[4][0] == y[4][0]) && (x[10][0] == 44) && (y[10][0] == 88)) - return 7; - return 0; - } + library Lib { + struct S { uint x; } + // a direct call to this should revert + function np(S storage s) public returns (address) { s.x = 3; return msg.sender; } + // a direct call to this is fine + function v(S storage) public view returns (address) { return msg.sender; } + // a direct call to this is fine + function pu() public pure returns (uint) { return 2; } + } + contract Test { + Lib.S public s; + function np() public returns (address) { return Lib.np(s); } + function v() public view returns (address) { return Lib.v(s); } + function pu() public pure returns (uint) { return Lib.pu(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); + compileAndRun(sourceCode, 0, "Lib"); + ABI_CHECK(callContractFunction("np(Lib.S storage)", 0), encodeArgs()); + ABI_CHECK(callContractFunction("v(Lib.S storage)", 0), encodeArgs(u160(m_sender))); + ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("s()"), encodeArgs(0)); + ABI_CHECK(callContractFunction("np()"), encodeArgs(u160(m_sender))); + ABI_CHECK(callContractFunction("s()"), encodeArgs(3)); + ABI_CHECK(callContractFunction("v()"), encodeArgs(u160(m_sender))); + ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); +} + +BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) +{ + char const* sourceCode = R"( + library Lib { + function x() public view returns (uint) { + return 1; + } + } + contract Test { + uint t; + function f() public returns (uint) { + t = 2; + return this.g(); + } + function g() public view returns (uint) { + return Lib.x(); + } + } + )"; + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); } -BOOST_AUTO_TEST_CASE(memory_overwrite) +BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) { char const* sourceCode = R"( contract C { - function f() public returns (bytes memory x) { - x = "12345"; - x[3] = 0x61; - x[0] = 0x62; + function f() public returns (bytes32) { + return keccak256(abi.encodePacked("abc", msg.data)); } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeDyn(string("b23a5"))); + bytes calldata1 = FixedHash<4>(util::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); + sendMessage(calldata1, false); + BOOST_CHECK(m_transactionSuccessful); + BOOST_CHECK(m_output == encodeArgs(util::keccak256(bytes{'a', 'b', 'c'} + calldata1))); } -BOOST_AUTO_TEST_CASE(addmod_mulmod) +BOOST_AUTO_TEST_CASE(call_forward_bytes) { char const* sourceCode = R"( - contract C { - function test() public returns (uint) { - // Note that this only works because computation on literals is done using - // unbounded integers. - if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) - return 1; - if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) - return 2; - return 0; - } + contract receiver { + uint public received; + function recv(uint x) public { received += x + 1; } + fallback() external { received = 0x80; } + } + contract sender { + constructor() public { rec = new receiver(); } + fallback() external { savedData = msg.data; } + function forward() public returns (bool) { address(rec).call(savedData); return true; } + function clear() public returns (bool) { delete savedData; return true; } + function val() public returns (uint) { return rec.received(); } + receiver rec; + bytes savedData; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "sender"); + ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes()); + ABI_CHECK(callContractFunction("val()"), encodeArgs(0)); + ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); + ABI_CHECK(callContractFunction("clear()"), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); + ABI_CHECK(callContractFunction("forward()"), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80)); } -BOOST_AUTO_TEST_CASE(addmod_mulmod_zero) +BOOST_AUTO_TEST_CASE(call_forward_bytes_length) { char const* sourceCode = R"( - contract C { - function f(uint d) public pure returns (uint) { - addmod(1, 2, d); - return 2; + contract receiver { + uint public calledLength; + fallback() external { calledLength = msg.data.length; } + } + contract sender { + receiver rec; + constructor() public { rec = new receiver(); } + function viaCalldata() public returns (uint) { + (bool success,) = address(rec).call(msg.data); + require(success); + return rec.calledLength(); } - function g(uint d) public pure returns (uint) { - mulmod(1, 2, d); - return 2; + function viaMemory() public returns (uint) { + bytes memory x = msg.data; + (bool success,) = address(rec).call(x); + require(success); + return rec.calledLength(); } - function h() public pure returns (uint) { - mulmod(0, 1, 2); - mulmod(1, 0, 2); - addmod(0, 1, 2); - addmod(1, 0, 2); - return 2; + bytes s; + function viaStorage() public returns (uint) { + s = msg.data; + (bool success,) = address(rec).call(s); + require(success); + return rec.calledLength(); } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("g(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); + compileAndRun(sourceCode, 0, "sender"); + + // No additional data, just function selector + ABI_CHECK(callContractFunction("viaCalldata()"), encodeArgs(4)); + ABI_CHECK(callContractFunction("viaMemory()"), encodeArgs(4)); + ABI_CHECK(callContractFunction("viaStorage()"), encodeArgs(4)); + + // Some additional unpadded data + bytes unpadded = asBytes(string("abc")); + ABI_CHECK(callContractFunctionNoEncoding("viaCalldata()", unpadded), encodeArgs(7)); + ABI_CHECK(callContractFunctionNoEncoding("viaMemory()", unpadded), encodeArgs(7)); + ABI_CHECK(callContractFunctionNoEncoding("viaStorage()", unpadded), encodeArgs(7)); } -BOOST_AUTO_TEST_CASE(divisiod_by_zero) +BOOST_AUTO_TEST_CASE(copying_bytes_multiassign) { char const* sourceCode = R"( - contract C { - function div(uint a, uint b) public returns (uint) { - return a / b; - } - function mod(uint a, uint b) public returns (uint) { - return a % b; + contract receiver { + uint public received; + function recv(uint x) public { received += x + 1; } + fallback() external { received = 0x80; } + } + contract sender { + constructor() public { rec = new receiver(); } + fallback() external { savedData1 = savedData2 = msg.data; } + function forward(bool selector) public returns (bool) { + if (selector) { address(rec).call(savedData1); delete savedData1; } + else { address(rec).call(savedData2); delete savedData2; } + return true; } + function val() public returns (uint) { return rec.received(); } + receiver rec; + bytes savedData1; + bytes savedData2; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("div(uint256,uint256)", 7, 2), encodeArgs(u256(3))); - // throws - ABI_CHECK(callContractFunction("div(uint256,uint256)", 7, 0), encodeArgs()); - ABI_CHECK(callContractFunction("mod(uint256,uint256)", 7, 2), encodeArgs(u256(1))); - // throws - ABI_CHECK(callContractFunction("mod(uint256,uint256)", 7, 0), encodeArgs()); + compileAndRun(sourceCode, 0, "sender"); + ABI_CHECK(callContractFunction("recv(uint256)", 7), bytes()); + ABI_CHECK(callContractFunction("val()"), encodeArgs(0)); + ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(8)); + ABI_CHECK(callContractFunction("forward(bool)", false), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(16)); + ABI_CHECK(callContractFunction("forward(bool)", true), encodeArgs(true)); + ABI_CHECK(callContractFunction("val()"), encodeArgs(0x80)); } -BOOST_AUTO_TEST_CASE(string_allocation_bug) +BOOST_AUTO_TEST_CASE(delete_removes_bytes_data) { char const* sourceCode = R"( - contract Sample - { - struct s { uint16 x; uint16 y; string a; string b;} - s[2] public p; - constructor() public { - s memory m; - m.x = 0xbbbb; - m.y = 0xcccc; - m.a = "hello"; - m.b = "world"; - p[0] = m; - } + contract c { + fallback() external { data = msg.data; } + function del() public returns (bool) { delete data; return true; } + bytes data; } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs( - u256(0xbbbb), - u256(0xcccc), - u256(0x80), - u256(0xc0), - u256(5), - string("hello"), - u256(5), - string("world") - )); + ABI_CHECK(callContractFunction("---", 7), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(using_for_function_on_int) +BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) { char const* sourceCode = R"( - library D { function double(uint self) public returns (uint) { return 2*self; } } - contract C { - using D for uint; - function f(uint a) public returns (uint) { - return a.double(); - } + contract c { + function set() public returns (bool) { data = msg.data; return true; } + fallback() external { data = msg.data; } + bytes data; } )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(9)), encodeArgs(u256(2 * 9))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + sendMessage(bytes(), false); + BOOST_CHECK(m_transactionSuccessful); + BOOST_CHECK(m_output.empty()); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(using_for_function_on_struct) +BOOST_AUTO_TEST_CASE(copy_removes_bytes_data) { char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 3; - return x.mul(a); - } + contract c { + function set() public returns (bool) { data1 = msg.data; return true; } + function reset() public returns (bool) { data1 = data2; return true; } + bytes data1; + bytes data2; + } + )"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("reset()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); +} + +BOOST_AUTO_TEST_CASE(bytes_inside_mappings) +{ + char const* sourceCode = R"( + contract c { + function set(uint key) public returns (bool) { data[key] = msg.data; return true; } + function copy(uint from, uint to) public returns (bool) { data[to] = data[from]; return true; } + mapping(uint => bytes) data; } )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(3 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(3 * 7))); + compileAndRun(sourceCode); + // store a short byte array at 1 and a longer one at 2 + ABI_CHECK(callContractFunction("set(uint256)", 1, 2), encodeArgs(true)); + ABI_CHECK(callContractFunction("set(uint256)", 2, 2, 3, 4, 5), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + // copy shorter to longer + ABI_CHECK(callContractFunction("copy(uint256,uint256)", 1, 2), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + // copy empty to both + ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 1), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("copy(uint256,uint256)", 99, 2), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(using_for_overload) +BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) { char const* sourceCode = R"( - library D { - struct s { uint a; } - function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } - function mul(s storage self, bytes32 x) public returns (bytes32) { } - } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return x.mul(a); + contract c { + struct Struct { uint a; bytes data; uint b; } + Struct data1; + Struct data2; + function set(uint _a, bytes calldata _data, uint _b) external returns (bool) { + data1.a = _a; + data1.b = _b; + data1.data = _data; + return true; + } + function copy() public returns (bool) { + data1 = data2; + return true; + } + function del() public returns (bool) { + delete data1; + return true; } } )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); + compileAndRun(sourceCode); + string data = "123456789012345678901234567890123"; + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("copy()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, 0x60, 13, u256(data.length()), data), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("del()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(using_for_by_name) +BOOST_AUTO_TEST_CASE(storing_invalid_boolean) { char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return x.mul({x: a}); + event Ev(bool); + bool public perm; + function set() public returns(uint) { + bool tmp; + assembly { + tmp := 5 + } + perm = tmp; + return 1; + } + function ret() public returns(bool) { + bool tmp; + assembly { + tmp := 5 + } + return tmp; + } + function ev() public returns(uint) { + bool tmp; + assembly { + tmp := 5 + } + emit Ev(tmp); + return 1; } } )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("set()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("perm()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("ret()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("ev()"), encodeArgs(1)); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_CHECK(logData(0) == encodeArgs(1)); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Ev(bool)"))); } -BOOST_AUTO_TEST_CASE(bound_function_in_function) +BOOST_AUTO_TEST_CASE(struct_referencing) { - char const* sourceCode = R"( + static char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + interface I { + struct S { uint a; } + } library L { - function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } + struct S { uint b; uint a; } + function f() public pure returns (S memory) { + S memory s; + s.a = 3; + return s; + } + function g() public pure returns (I.S memory) { + I.S memory s; + s.a = 4; + return s; + } + // argument-dependant lookup tests + function a(I.S memory) public pure returns (uint) { return 1; } + function a(S memory) public pure returns (uint) { return 2; } } - contract C { - using L for *; - function f() public returns (uint) { - return t.g(); + contract C is I { + function f() public pure returns (S memory) { + S memory s; + s.a = 1; + return s; } - function t() public pure returns (uint) { return 7; } + function g() public pure returns (I.S memory) { + I.S memory s; + s.a = 2; + return s; + } + function h() public pure returns (L.S memory) { + L.S memory s; + s.a = 5; + return s; + } + function x() public pure returns (L.S memory) { + return L.f(); + } + function y() public pure returns (I.S memory) { + return L.g(); + } + function a1() public pure returns (uint) { S memory s; return L.a(s); } + function a2() public pure returns (uint) { L.S memory s; return L.a(s); } } )"; compileAndRun(sourceCode, 0, "L"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0, 3)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(4)); + compileAndRun(sourceCode, 0, "C", bytes(), map{ {"L", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); + ABI_CHECK(callContractFunction("h()"), encodeArgs(0, 5)); + ABI_CHECK(callContractFunction("x()"), encodeArgs(0, 3)); + ABI_CHECK(callContractFunction("y()"), encodeArgs(4)); + ABI_CHECK(callContractFunction("a1()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("a2()"), encodeArgs(2)); } -BOOST_AUTO_TEST_CASE(bound_function_in_var) +BOOST_AUTO_TEST_CASE(enum_referencing) { char const* sourceCode = R"( - library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } - contract C { - using D for D.s; - D.s public x; - function f(uint a) public returns (uint) { - x.a = 6; - return (x.mul)({x: a}); + interface I { + enum Direction { A, B, Left, Right } + } + library L { + enum Direction { Left, Right } + function f() public pure returns (Direction) { + return Direction.Right; + } + function g() public pure returns (I.Direction) { + return I.Direction.Right; } } - )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); -} - -BOOST_AUTO_TEST_CASE(bound_function_to_string) -{ - char const* sourceCode = R"( - library D { function length(string memory self) public returns (uint) { return bytes(self).length; } } - contract C { - using D for string; - string x; - function f() public returns (uint) { - x = "abc"; - return x.length(); + contract C is I { + function f() public pure returns (Direction) { + return Direction.Right; } - function g() public returns (uint) { - string memory s = "abc"; - return s.length(); + function g() public pure returns (I.Direction) { + return I.Direction.Right; + } + function h() public pure returns (L.Direction) { + return L.Direction.Right; + } + function x() public pure returns (L.Direction) { + return L.f(); + } + function y() public pure returns (I.Direction) { + return L.g(); } } )"; - compileAndRun(sourceCode, 0, "D"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(3))); + compileAndRun(sourceCode, 0, "L"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); + ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); + ABI_CHECK(callContractFunction("h()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("x()"), encodeArgs(1)); + ABI_CHECK(callContractFunction("y()"), encodeArgs(3)); } -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_strings) +BOOST_AUTO_TEST_CASE(bytes_in_arguments) { char const* sourceCode = R"( - contract C { - string s = "doh"; - function f() public returns (string memory, string memory) { - string memory t = "ray"; - string[3] memory x = [s, t, "mi"]; - return (x[1], x[2]); + contract c { + uint result; + function f(uint a, uint b) public { result += a + b; } + function g(uint a) public { result *= a; } + function test(uint a, bytes calldata data1, bytes calldata data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) { + r_a = a; + address(this).call(data1); + address(this).call(data2); + r = result; + r_b = b; + l = data1.length; } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x40), u256(0x80), u256(3), string("ray"), u256(2), string("mi"))); + + string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); + string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); + bytes calldata = encodeArgs( + 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, + u256(innercalldata1.length()), innercalldata1, + u256(innercalldata2.length()), innercalldata2); + ABI_CHECK( + callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), + encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) + ); } -BOOST_AUTO_TEST_CASE(inline_array_strings_from_document) +BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) { char const* sourceCode = R"( - contract C { - function f(uint i) public returns (string memory) { - string[4] memory x = ["This", "is", "an", "array"]; - return (x[i]); - } + contract c { + struct Data { uint x; uint y; } + Data[2**10] data; + uint[2**10 + 3] ids; + function setIDStatic(uint id) public { ids[2] = id; } + function setID(uint index, uint id) public { ids[index] = id; } + function setData(uint index, uint x, uint y) public { data[index].x = x; data[index].y = y; } + function getID(uint index) public returns (uint) { return ids[index]; } + function getData(uint index) public returns (uint x, uint y) { x = data[index].x; y = data[index].y; } + function getLengths() public returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } } )"; compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0x20), u256(4), string("This"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(0x20), u256(2), string("is"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0x20), u256(2), string("an"))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(0x20), u256(5), string("array"))); + ABI_CHECK(callContractFunction("setIDStatic(uint256)", 11), bytes()); + ABI_CHECK(callContractFunction("getID(uint256)", 2), encodeArgs(11)); + ABI_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8), bytes()); + ABI_CHECK(callContractFunction("getID(uint256)", 7), encodeArgs(8)); + ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9), bytes()); + ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11), bytes()); + ABI_CHECK(callContractFunction("getData(uint256)", 7), encodeArgs(8, 9)); + ABI_CHECK(callContractFunction("getData(uint256)", 8), encodeArgs(10, 11)); + ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); } -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_ints) +BOOST_AUTO_TEST_CASE(fixed_array_cleanup) { char const* sourceCode = R"( - contract C { - function f() public returns (uint x, uint y) { - x = 3; - y = 6; - uint[2] memory z = [x, y]; - return (z[0], z[1]); + contract c { + uint spacer1; + uint spacer2; + uint[20] data; + function fill() public { + for (uint i = 0; i < data.length; ++i) data[i] = i+1; } + function clear() public { delete data; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3, 6)); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } -BOOST_AUTO_TEST_CASE(inline_array_index_access_ints) +BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup) { char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return ([1, 2, 3, 4][2]); + contract c { + uint spacer1; + uint spacer2; + uint[3] data; + function fill() public { + for (uint i = 0; i < data.length; ++i) data[i] = i+1; } + function clear() public { delete data; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } -BOOST_AUTO_TEST_CASE(inline_array_index_access_strings) +BOOST_AUTO_TEST_CASE(dynamic_array_cleanup) { char const* sourceCode = R"( - contract C { - string public tester; - function f() public returns (string memory) { - return (["abc", "def", "g"][0]); + contract c { + uint[20] spacer; + uint[] dynamic; + function fill() public { + for (uint i = 0; i < 21; ++i) + dynamic.push(i + 1); } - function test() public { - tester = f(); + function halfClear() public { + while (dynamic.length > 5) + dynamic.pop(); } + function fullClear() public { delete dynamic; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - ABI_CHECK(callContractFunction("tester()"), encodeArgs(u256(0x20), u256(3), string("abc"))); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("halfClear()"), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fullClear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } -BOOST_AUTO_TEST_CASE(inline_array_return) +BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) { char const* sourceCode = R"( - contract C { - uint8[] tester; - function f() public returns (uint8[5] memory) { - return ([1,2,3,4,5]); - } - function test() public returns (uint8, uint8, uint8, uint8, uint8) { - tester = f(); - return (tester[0], tester[1], tester[2], tester[3], tester[4]); + contract c { + struct s { uint[][] d; } + s[] data; + function fill() public returns (uint) { + while (data.length < 3) + data.push(); + while (data[2].d.length < 4) + data[2].d.push(); + while (data[2].d[3].length < 5) + data[2].d[3].push(); + data[2].d[3][4] = 8; + return data[2].d[3][4]; } - + function clear() public { delete data; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1, 2, 3, 4, 5)); + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_array_singleton) +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) { - // This caused a failure since the type was not converted to its mobile type. char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return [4][0]; + contract c { + uint[] data1; + uint[] data2; + function setData1(uint length, uint index, uint value) public { + data1 = new uint[](length); + if (index < length) + data1[index] = value; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(inline_long_string_return) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (string memory) { - return (["somethingShort", "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"][1]); + function copyStorageStorage() public { data2 = data1; } + function getData2(uint index) public returns (uint len, uint val) { + len = data2.length; if (index < len) val = data2[index]; } } )"; - - string strLong = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeDyn(strLong)); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4), bytes()); + ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes()); + ABI_CHECK(callContractFunction("getData2(uint256)", 5), encodeArgs(10, 4)); + ABI_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0), bytes()); + ABI_CHECK(callContractFunction("copyStorageStorage()"), bytes()); + ABI_CHECK(callContractFunction("getData2(uint256)", 0), encodeArgs(0, 0)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(fixed_bytes_index_access) +BOOST_AUTO_TEST_CASE(array_copy_target_leftover) { + // test that leftover elements in the last slot of target are correctly cleared during assignment char const* sourceCode = R"( - contract C { - bytes16[] public data; - function f(bytes32 x) public returns (byte) { - return x[2]; - } - function g(bytes32 x) public returns (uint) { - data = [x[0], x[1], x[2]]; - data[0] = "12345"; - return uint(uint8(data[0][4])); + contract c { + byte[10] data1; + bytes2[32] data2; + function test() public returns (uint check, uint res1, uint res2) { + uint i; + for (i = 0; i < data2.length; ++i) + data2[i] = 0xffff; + check = uint(uint16(data2[31])) * 0x10000 | uint(uint16(data2[14])); + for (i = 0; i < data1.length; ++i) + data1[i] = byte(uint8(1 + i)); + data2 = data1; + for (i = 0; i < 16; ++i) + res1 |= uint(uint16(data2[i])) * 0x10000**i; + for (i = 0; i < 16; ++i) + res2 |= uint(uint16(data2[16 + i])) * 0x10000**i; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs("9")); - ABI_CHECK(callContractFunction("g(bytes32)", "789"), encodeArgs(u256(int('5')))); - ABI_CHECK(callContractFunction("data(uint256)", u256(1)), encodeArgs("8")); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(u256("0xffffffff"), asString(fromHex("0000000000000000000000000a00090008000700060005000400030002000100")), asString(fromHex("0000000000000000000000000000000000000000000000000000000000000000")))); } -BOOST_AUTO_TEST_CASE(fixed_bytes_length_access) +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) { char const* sourceCode = R"( - contract C { - byte a; - function f(bytes32 x) public returns (uint, uint, uint) { - return (x.length, bytes16(uint128(2)).length, a.length + 7); + contract c { + struct Data { uint x; uint y; } + Data[] data1; + Data[] data2; + function test() public returns (uint x, uint y) { + while (data1.length < 9) + data1.push(); + data1[8].x = 4; + data1[8].y = 5; + data2 = data1; + x = data2[8].x; + y = data2[8].y; + while (data1.length > 0) + data1.pop(); + data2 = data1; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs(u256(32), u256(16), u256(8))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(4, 5)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(byte_optimization_bug) +BOOST_AUTO_TEST_CASE(array_copy_storage_abi) { + // NOTE: This does not really test copying from storage to ABI directly, + // because it will always copy to memory first. char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint a) { - assembly { - a := byte(x, 31) - } + pragma experimental ABIEncoderV2; + contract c { + uint8[] x; + uint16[] y; + uint24[] z; + uint24[][] w; + function test1() public returns (uint8[] memory) { + for (uint i = 0; i < 101; ++i) + x.push(uint8(i)); + return x; } - function g(uint x) public returns (uint a) { - assembly { - a := byte(31, x) - } + function test2() public returns (uint16[] memory) { + for (uint i = 0; i < 101; ++i) + y.push(uint16(i)); + return y; + } + function test3() public returns (uint24[] memory) { + for (uint i = 0; i < 101; ++i) + z.push(uint24(i)); + return z; + } + function test4() public returns (uint24[][] memory) { + w = new uint24[][](5); + for (uint i = 0; i < 5; ++i) + for (uint j = 0; j < 101; ++j) + w[i].push(uint24(j)); + return w; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("g(uint256)", u256(2)), encodeArgs(u256(2))); - ) + compileAndRun(sourceCode); + bytes valueSequence; + for (size_t i = 0; i < 101; ++i) + valueSequence += toBigEndian(u256(i)); + ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test4()"), + encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + ); } -BOOST_AUTO_TEST_CASE(inline_assembly_write_to_stack) +BOOST_AUTO_TEST_CASE(array_pop_uint16_transition) { char const* sourceCode = R"( - contract C { - function f() public returns (uint r, bytes32 r2) { - assembly { r := 7 r2 := "abcdef" } + contract c { + uint16[] data; + function test() public returns (uint16 x, uint16 y, uint16 z) { + for (uint i = 1; i <= 48; i++) + data.push(uint16(i)); + for (uint j = 1; j <= 10; j++) + data.pop(); + x = data[data.length - 1]; + for (uint k = 1; k <= 10; k++) + data.pop(); + y = data[data.length - 1]; + for (uint l = 1; l <= 10; l++) + data.pop(); + z = data[data.length - 1]; + for (uint m = 1; m <= 18; m++) + data.pop(); } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), string("abcdef"))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_read_and_write_stack) +BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) { char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - for (uint x = 0; x < 10; ++x) - assembly { r := add(r, x) } + contract c { + uint256 a; + uint256 b; + uint256 c; + uint24[] data; + function test() public returns (uint24 x, uint24 y) { + for (uint i = 1; i <= 30; i++) + data.push(uint24(i)); + for (uint j = 1; j <= 10; j++) + data.pop(); + x = data[data.length - 1]; + for (uint k = 1; k <= 10; k++) + data.pop(); + y = data[data.length - 1]; + for (uint l = 1; l <= 10; l++) + data.pop(); } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(45))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_memory_access) +BOOST_AUTO_TEST_CASE(array_pop_array_transition) { char const* sourceCode = R"( - contract C { - function test() public returns (bytes memory) { - bytes memory x = new bytes(5); - for (uint i = 0; i < x.length; ++i) - x[i] = byte(uint8(i + 1)); - assembly { mstore(add(x, 32), "12345678901234567890123456789012") } - return x; + contract c { + uint256 a; + uint256 b; + uint256 c; + uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + uint16[][] data; + function test() public returns (uint x, uint y, uint z) { + for (uint i = 1; i <= 48; i++) + data.push(inner); + for (uint j = 1; j <= 10; j++) + data.pop(); + x = data[data.length - 1][0]; + for (uint k = 1; k <= 10; k++) + data.pop(); + y = data[data.length - 1][1]; + for (uint l = 1; l <= 10; l++) + data.pop(); + z = data[data.length - 1][2]; + for (uint m = 1; m <= 18; m++) + data.pop(); + delete inner; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0x20), u256(5), string("12345"))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(1, 2, 3)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access) +BOOST_AUTO_TEST_CASE(array_pop_storage_empty) { char const* sourceCode = R"( - contract C { - uint16 x; - uint16 public y; - uint public z; - function f() public returns (bool) { - uint off1; - uint off2; - assembly { - sstore(z_slot, 7) - off1 := z_offset - off2 := y_offset - } - assert(off1 == 0); - assert(off2 == 2); - return true; + contract c { + uint[] data; + function test() public { + data.push(7); + data.pop(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_inside_function) +BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) { char const* sourceCode = R"( - contract C { - uint16 x; - uint16 public y; - uint public z; - function f() public returns (bool) { - uint off1; - uint off2; - assembly { - function f() -> o1 { - sstore(z_slot, 7) - o1 := y_offset - } - off2 := f() - } - assert(off2 == 2); - return true; + contract c { + bytes data; + function test() public { + data.push(0x07); + data.push(0x05); + data.push(0x03); + data.pop(); + data.pop(); + data.pop(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_via_pointer) +BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) { char const* sourceCode = R"( - contract C { - struct Data { uint contents; } - uint public separator; - Data public a; - uint public separator2; - function f() public returns (bool) { - Data storage x = a; - uint off; - assembly { - sstore(x_slot, 7) - off := x_offset + contract c { + uint256 a; + uint256 b; + uint256 c; + bytes data; + function test() public returns (bool) { + for (uint8 i = 0; i <= 40; i++) + data.push(byte(i+1)); + for (int8 j = 40; j >= 0; j--) { + require(data[uint8(j)] == byte(j+1)); + require(data.length == uint8(j+1)); + data.pop(); } - assert(off == 0); return true; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("separator()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("separator2()"), encodeArgs(u256(0))); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_function_call) +BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) { char const* sourceCode = R"( - contract C { - function f() public { - assembly { - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 + contract c { + uint256 a; + uint256 b; + bytes data; + function test() public { + for (uint8 i = 0; i <= 40; i++) + data.push(0x03); + for (uint8 j = 0; j <= 40; j++) { + assembly { + mstore(0, "garbage") } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - return(0, 0x60) + data.pop(); } } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment) +BOOST_AUTO_TEST_CASE(external_array_args) { char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let a1, b1, c1 - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 - } - a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - return(0, 0x60) - } + contract c { + function test(uint[8] calldata a, uint[] calldata b, uint[5] calldata c, uint a_index, uint b_index, uint c_index) + external returns (uint av, uint bv, uint cv) { + av = a[a_index]; + bv = b[b_index]; + cv = c[c_index]; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) + compileAndRun(sourceCode); + bytes params = encodeArgs( + 1, 2, 3, 4, 5, 6, 7, 8, // a + 32 * (8 + 1 + 5 + 1 + 1 + 1), // offset to b + 21, 22, 23, 24, 25, // c + 0, 1, 2, // (a,b,c)_index + 3, // b.length + 11, 12, 13 // b + ); + ABI_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params), encodeArgs(1, 12, 23)); } -BOOST_AUTO_TEST_CASE(inline_assembly_function_call2) +BOOST_AUTO_TEST_CASE(bytes_index_access) { char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let d := 0x10 - function asmfun(a, b, c) -> x, y, z { - x := a - y := b - z := 7 - } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - mstore(0x60, d) - return(0, 0x80) - } + contract c { + bytes data; + function direct(bytes calldata arg, uint index) external returns (uint) { + return uint(uint8(arg[index])); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7), u256(0x10))); - ) -} + function storageCopyRead(bytes calldata arg, uint index) external returns (uint) { + data = arg; + return uint(uint8(data[index])); + } + function storageWrite() external returns (uint) { + data = new bytes(35); + data[31] = 0x77; + data[32] = 0x14; -BOOST_AUTO_TEST_CASE(inline_assembly_embedded_function_call) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - let d := 0x10 - function asmfun(a, b, c) -> x, y, z { - x := g(a) - function g(r) -> s { s := mul(r, r) } - y := g(b) - z := 7 - } - let a1, b1, c1 := asmfun(1, 2, 3) - mstore(0x00, a1) - mstore(0x20, b1) - mstore(0x40, c1) - mstore(0x60, d) - return(0, 0x80) - } + data[31] = 0x01; + data[31] |= 0x08; + data[30] = 0x01; + data[32] = 0x03; + return uint(uint8(data[30])) * 0x100 | uint(uint8(data[31])) * 0x10 | uint(uint8(data[32])); } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(4), u256(7), u256(0x10))); - ) + compileAndRun(sourceCode); + string array{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33}; + ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); } -BOOST_AUTO_TEST_CASE(inline_assembly_if) +BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) { char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - if gt(a, 1) { b := 2 } - } + contract c { + uint[9] m_data; + uint[] m_data_dyn; + uint8[][] m_byte_data; + function store(uint[9] calldata a, uint8[3][] calldata b) external returns (uint8) { + m_data = a; + m_data_dyn = a; + m_byte_data = b; + return b[3][1]; // note that access and declaration are reversed to each other + } + function retrieve() public returns (uint a, uint b, uint c, uint d, uint e, uint f, uint g) { + a = m_data.length; + b = m_data[7]; + c = m_data_dyn.length; + d = m_data_dyn[7]; + e = m_byte_data.length; + f = m_byte_data[3].length; + g = m_byte_data[3][1]; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(2))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs(21, 22, 23, 24, 25, 26, 27, 28, 29, u256(32 * (9 + 1)), 4, 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33 )), encodeArgs(32)); + ABI_CHECK(callContractFunction("retrieve()"), encodeArgs(9, 28, 9, 28, 4, 3, 32)); } -BOOST_AUTO_TEST_CASE(inline_assembly_switch) +BOOST_AUTO_TEST_CASE(array_copy_including_mapping) { char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - switch a - case 1 { b := 8 } - case 2 { b := 9 } - default { b := 2 } + contract c { + mapping(uint=>uint)[90][] large; + mapping(uint=>uint)[3][] small; + function test() public returns (uint r) { + for (uint i = 0; i < 7; i++) { + large.push(); + small.push(); } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(9))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(2))); - ) -} + large[3][2][0] = 2; + large[1] = large[3]; + small[3][2][0] = 2; + small[1] = small[2]; + r = (( + small[3][2][0] * 0x100 | + small[1][2][0]) * 0x100 | + large[3][2][0]) * 0x100 | + large[1][2][0]; + delete small; + delete large; -BOOST_AUTO_TEST_CASE(inline_assembly_recursion) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - function fac(n) -> nf { - switch n - case 0 { nf := 1 } - case 1 { nf := 1 } - default { nf := mul(n, fac(sub(n, 1))) } - } - b := fac(a) + } + function clear() public returns (uint, uint) { + for (uint i = 0; i < 7; i++) { + large.push(); + small.push(); } + small[3][2][0] = 0; + large[3][2][0] = 0; + while (small.length > 0) + small.pop(); + while (large.length > 0) + large.pop(); + return (small.length, large.length); } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("f(uint256)", u256(4)), encodeArgs(u256(24))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(0x02000200)); + // storage is not empty because we cannot delete the mappings + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), encodeArgs(0, 0)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(inline_assembly_for) +BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) { char const* sourceCode = R"( contract C { - function f(uint a) public returns (uint b) { - assembly { - function fac(n) -> nf { - nf := 1 - for { let i := n } gt(i, 0) { i := sub(i, 1) } { - nf := mul(nf, i) - } - } - b := fac(a) - } - } + bytes32 constant x = keccak256("abc"); + function f() public returns (bytes32) { return x; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("f(uint256)", u256(4)), encodeArgs(u256(24))); - ) + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(util::keccak256("abc"))); } -BOOST_AUTO_TEST_CASE(inline_assembly_for2) +// Disabled until https://github.com/ethereum/solidity/issues/715 is implemented +//BOOST_AUTO_TEST_CASE(assignment_to_const_array_vars) +//{ +// char const* sourceCode = R"( +// contract C { +// uint[3] constant x = [uint(1), 2, 3]; +// uint constant y = x[0] + x[1] + x[2]; +// function f() public returns (uint) { return y; } +// } +// )"; +// compileAndRun(sourceCode); +// ABI_CHECK(callContractFunction("f()"), encodeArgs(1 + 2 + 3)); +//} + +// Disabled until https://github.com/ethereum/solidity/issues/715 is implemented +//BOOST_AUTO_TEST_CASE(constant_struct) +//{ +// char const* sourceCode = R"( +// contract C { +// struct S { uint x; uint[] y; } +// S constant x = S(5, new uint[](4)); +// function f() public returns (uint) { return x.x; } +// } +// )"; +// compileAndRun(sourceCode); +// ABI_CHECK(callContractFunction("f()"), encodeArgs(5)); +//} + +BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) { char const* sourceCode = R"( contract C { - uint st; - function f(uint a) public returns (uint b, uint c, uint d) { - st = 0; - assembly { - function sideeffect(r) -> x { sstore(0, add(sload(0), r)) x := 1} - for { let i := a } eq(i, sideeffect(2)) { d := add(d, 3) } { - b := i - i := 0 - } - } - c = st; + struct str { uint8 a; uint16 b; uint8 c; } + uint8 x; + uint16 y; + str data; + function test() public returns (uint) { + x = 1; + y = 2; + data.a = 2; + data.b = 0xabcd; + data.c = 0xfa; + if (x != 1 || y != 2 || data.a != 2 || data.b != 0xabcd || data.c != 0xfa) + return 2; + delete y; + delete data.b; + if (x != 1 || y != 0 || data.a != 2 || data.b != 0 || data.c != 0xfa) + return 3; + delete x; + delete data; + return 1; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", u256(0)), encodeArgs(u256(0), u256(2), u256(0))); - ABI_CHECK(callContractFunction("f(uint256)", u256(1)), encodeArgs(u256(1), u256(4), u256(3))); - ABI_CHECK(callContractFunction("f(uint256)", u256(2)), encodeArgs(u256(0), u256(2), u256(0))); - ) -} - -BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) -{ - // Test for a bug where higher order bits cleanup was not done for array index access. - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint[256] memory r){ - r[uint8(x)] = 2; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // neither of the two should throw due to out-of-bounds access - BOOST_CHECK(callContractFunction("f(uint256)", u256(0x01)).size() == 256 * 32); - BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(1)); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(delete_on_array_of_structs) +BOOST_AUTO_TEST_CASE(bool_conversion) { - // Test for a bug where we did not increment the counter properly while deleting a dynamic array. char const* sourceCode = R"( contract C { - struct S { uint x; uint[] y; } - S[] data; - function f() public returns (bool) { - S storage s1 = data.push(); - s1.x = 2**200; - S storage s2 = data.push(); - s2.x = 2**200; - delete data; - return true; + function f(bool _b) public returns(uint) { + if (_b) + return 1; + else + return 0; + } + function g(bool _in) public returns (bool _out) { + _out = _in; } } )"; compileAndRun(sourceCode, 0, "C"); - // This code interprets x as an array length and thus will go out of gas. - // neither of the two should throw due to out-of-bounds access - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(bool)", 0), encodeArgs(0)); + ABI_CHECK(callContractFunction("f(bool)", 1), encodeArgs(1)); + ABI_CHECK(callContractFunction("f(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); + ABI_CHECK(callContractFunction("f(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); + ABI_CHECK(callContractFunction("f(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); + ABI_CHECK(callContractFunction("g(bool)", 0), encodeArgs(0)); + ABI_CHECK(callContractFunction("g(bool)", 1), encodeArgs(1)); + ABI_CHECK(callContractFunction("g(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); + ABI_CHECK(callContractFunction("g(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); + ABI_CHECK(callContractFunction("g(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); } -BOOST_AUTO_TEST_CASE(internal_library_function) +BOOST_AUTO_TEST_CASE(invalid_enum_logged) { - // tests that internal library functions can be called from outside - // and retain the same memory context (i.e. are pulled into the caller's code) char const* sourceCode = R"( - library L { - function f(uint[] memory _data) internal { - _data[3] = 2; - } - } contract C { - function f() public returns (uint) { - uint[] memory x = new uint[](7); - x[3] = 8; - L.f(x); - return x[3]; + enum X { A, B } + event Log(X); + + function test_log() public returns (uint) { + X garbled = X.A; + assembly { + garbled := 5 + } + emit Log(garbled); + return 1; + } + function test_log_ok() public returns (uint) { + X x = X.A; + emit Log(x); + return 1; } } - )"; - // This has to work without linking, because everything will be inlined. + )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); + ABI_CHECK(callContractFunction("test_log_ok()"), encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(numLogs(), 1); + BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); + BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); + BOOST_REQUIRE_EQUAL(logTopic(0, 0), util::keccak256(string("Log(uint8)"))); + BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0))); + + // should throw + ABI_CHECK(callContractFunction("test_log()"), encodeArgs()); } -BOOST_AUTO_TEST_CASE(internal_library_function_calling_private) +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) { - // tests that internal library functions that are called from outside and that - // themselves call private functions are still able to (i.e. the private function - // also has to be pulled into the caller's code) char const* sourceCode = R"( - library L { - function g(uint[] memory _data) private { - _data[3] = 2; - } - function f(uint[] memory _data) internal { - g(_data); - } - } - contract C { - function f() public returns (uint) { - uint[] memory x = new uint[](7); - x[3] = 8; - L.f(x); - return x[3]; + contract A { + uint public test = 1; + uint[3] arr; + constructor() public + { + uint index = 5; + test = arr[index]; + ++test; } } )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); + ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs()); + BOOST_CHECK(!m_transactionSuccessful); } -BOOST_AUTO_TEST_CASE(internal_library_function_bound) +BOOST_AUTO_TEST_CASE(failing_send) { char const* sourceCode = R"( - library L { - struct S { uint[] data; } - function f(S memory _s) internal { - _s.data[3] = 2; + contract Helper { + uint[] data; + fallback () external { + data[9]; // trigger exception } } - contract C { - using L for L.S; - function f() public returns (uint) { - L.S memory x; - x.data = new uint[](7); - x.data[3] = 8; - x.f(); - return x.data[3]; + contract Main { + constructor() public payable {} + function callHelper(address payable _a) public returns (bool r, uint bal) { + r = !_a.send(5); + bal = address(this).balance; } } )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); + compileAndRun(sourceCode, 0, "Helper"); + u160 const c_helperAddress = m_contractAddress; + compileAndRun(sourceCode, 20, "Main"); + BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); } -BOOST_AUTO_TEST_CASE(internal_library_function_return_var_size) +BOOST_AUTO_TEST_CASE(reusing_memory) { + // Invoke some features that use memory and test that they do not interfere with each other. char const* sourceCode = R"( - library L { - struct S { uint[] data; } - function f(S memory _s) internal returns (uint[] memory) { - _s.data[3] = 2; - return _s.data; + contract Helper { + uint public flag; + constructor(uint x) public { + flag = x; } } - contract C { - using L for L.S; - function f() public returns (uint) { - L.S memory x; - x.data = new uint[](7); - x.data[3] = 8; - return x.f()[3]; + contract Main { + mapping(uint => uint) map; + function f(uint x) public returns (uint) { + map[x] = x; + return (new Helper(uint(keccak256(abi.encodePacked(this.g(map[x])))))).flag(); + } + function g(uint a) public returns (uint) + { + return map[a]; } } )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); + compileAndRun(sourceCode, 0, "Main"); + BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(util::keccak256(util::toBigEndian(u256(0x34))))); } -BOOST_AUTO_TEST_CASE(iszero_bnot_correct) +BOOST_AUTO_TEST_CASE(return_string) { - // A long time ago, some opcodes were renamed, which involved the opcodes - // "iszero" and "not". char const* sourceCode = R"( - contract C { - function f() public returns (bool) { - bytes32 x = bytes32(uint256(1)); - assembly { x := not(x) } - if (x != ~bytes32(uint256(1))) return false; - assembly { x := iszero(x) } - if (x != bytes32(0)) return false; - return true; + contract Main { + string public s; + function set(string calldata _s) external { + s = _s; + } + function get1() public returns (string memory r) { + return s; + } + function get2() public returns (string memory r) { + r = s; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); + compileAndRun(sourceCode, 0, "Main"); + string s("Julia"); + bytes args = encodeArgs(u256(0x20), u256(s.length()), s); + BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs()); + ABI_CHECK(callContractFunction("get1()"), args); + ABI_CHECK(callContractFunction("get2()"), args); + ABI_CHECK(callContractFunction("s()"), args); } -BOOST_AUTO_TEST_CASE(cleanup_bytes_types) +BOOST_AUTO_TEST_CASE(return_multiple_strings_of_various_sizes) { - // Checks that bytesXX types are properly cleaned before they are compared. char const* sourceCode = R"( - contract C { - function f(bytes2 a, uint16 x) public returns (uint) { - if (a != "ab") return 1; - if (x != 0x0102) return 2; - if (bytes3(uint24(x)) != 0x000102) return 3; - return 0; + contract Main { + string public s1; + string public s2; + function set(string calldata _s1, uint x, string calldata _s2) external returns (uint) { + s1 = _s1; + s2 = _s2; + return x; + } + function get() public returns (string memory r1, string memory r2) { + r1 = s1; + r2 = s2; } } )"; - compileAndRun(sourceCode, 0, "C"); - // We input longer data on purpose. - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), v2 ? encodeArgs() : encodeArgs(0)); + compileAndRun(sourceCode, 0, "Main"); + string s1( + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + ); + string s2( + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + "ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ" + ); + vector lengths{0, 30, 32, 63, 64, 65, 210, 300}; + for (auto l1: lengths) + for (auto l2: lengths) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); + bytes args = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; + BOOST_REQUIRE( + callContractFunction("set(string,uint256,string)", asString(args)) == + encodeArgs(u256(l1)) + ); + bytes result = encodeArgs(u256(0x40), u256(0x40 + dyn1.size())) + dyn1 + dyn2; + ABI_CHECK(callContractFunction("get()"), result); + ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1); + ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2); + } } -BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening) + +BOOST_AUTO_TEST_CASE(accessor_involving_strings) { char const* sourceCode = R"( - contract C { - function f() public pure returns (bytes32 r) { - bytes4 x = 0xffffffff; - bytes2 y = bytes2(x); - assembly { r := y } - // At this point, r and y both store four bytes, but - // y is properly cleaned before the equality check - require(y == bytes2(0xffff)); + contract Main { + struct stringData { string a; uint b; string c; } + mapping(uint => stringData[]) public data; + function set(uint x, uint y, string calldata a, uint b, string calldata c) external returns (bool) { + while (data[x].length < y + 1) + data[x].push(); + data[x][y].a = a; + data[x][y].b = b; + data[x][y].c = c; + return true; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs("\xff\xff\xff\xff")); + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); + bytes s1Data = encodeArgs(u256(s1.length()), s1); + bytes s2Data = encodeArgs(u256(s2.length()), s2); + u256 b = 765; + u256 x = 7; + u256 y = 123; + bytes args = encodeArgs(x, y, u256(0xa0), b, u256(0xa0 + s1Data.size()), s1Data, s2Data); + bytes result = encodeArgs(u256(0x60), b, u256(0x60 + s1Data.size()), s1Data, s2Data); + BOOST_REQUIRE(callContractFunction("set(uint256,uint256,string,uint256,string)", asString(args)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); } -BOOST_AUTO_TEST_CASE(cleanup_address_types) + +BOOST_AUTO_TEST_CASE(bytes_in_function_calls) { - // Checks that address types are properly cleaned before they are compared. char const* sourceCode = R"( - contract C { - function f(address a) public returns (uint) { - if (a != 0x1234567890123456789012345678901234567890) return 1; - return 0; + contract Main { + string public s1; + string public s2; + function set(string memory _s1, uint x, string memory _s2) public returns (uint) { + s1 = _s1; + s2 = _s2; + return x; } - function g(address payable a) public returns (uint) { - if (a != 0x1234567890123456789012345678901234567890) return 1; - return 0; + function setIndirectFromMemory(string memory _s1, uint x, string memory _s2) public returns (uint) { + return this.set(_s1, x, _s2); + } + function setIndirectFromCalldata(string calldata _s1, uint x, string calldata _s2) external returns (uint) { + return this.set(_s1, x, _s2); } } )"; - compileAndRun(sourceCode, 0, "C"); - - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - // We input longer data on purpose. - ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); - ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); + vector lengths{0, 31, 64, 65}; + for (auto l1: lengths) + for (auto l2: lengths) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); + bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; + BOOST_REQUIRE( + callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) == + encodeArgs(u256(l1)) + ); + ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn1); + ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn2); + // swapped + bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1; + BOOST_REQUIRE( + callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) == + encodeArgs(u256(l1)) + ); + ABI_CHECK(callContractFunction("s1()"), encodeArgs(0x20) + dyn2); + ABI_CHECK(callContractFunction("s2()"), encodeArgs(0x20) + dyn1); + } } -BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening) +BOOST_AUTO_TEST_CASE(return_bytes_internal) { char const* sourceCode = R"( - contract C { - function f() public pure returns (address r) { - bytes21 x = 0x1122334455667788990011223344556677889900ff; - bytes20 y; - assembly { y := x } - address z = address(y); - assembly { r := z } - require(z == 0x1122334455667788990011223344556677889900); + contract Main { + bytes s1; + function doSet(bytes memory _s1) public returns (bytes memory _r1) { + s1 = _s1; + _r1 = s1; } - function g() public pure returns (address payable r) { - bytes21 x = 0x1122334455667788990011223344556677889900ff; - bytes20 y; - assembly { y := x } - address payable z = address(y); - assembly { r := z } - require(z == 0x1122334455667788990011223344556677889900); + function set(bytes calldata _s1) external returns (uint _r, bytes memory _r1) { + _r1 = doSet(_s1); + _r = _r1.length; } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ) + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + vector lengths{0, 31, 64, 65}; + for (auto l1: lengths) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes args1 = encodeArgs(u256(0x20)) + dyn1; + BOOST_REQUIRE( + callContractFunction("set(bytes)", asString(args1)) == + encodeArgs(u256(l1), u256(0x40)) + dyn1 + ); + } } -BOOST_AUTO_TEST_CASE(skip_dynamic_types) +BOOST_AUTO_TEST_CASE(bytes_index_access_memory) { - // The EVM cannot provide access to dynamically-sized return values, so we have to skip them. char const* sourceCode = R"( - contract C { - function f() public returns (uint, uint[] memory, uint) { - return (7, new uint[](2), 8); + contract Main { + function f(bytes memory _s1, uint i1, uint i2, uint i3) public returns (byte c1, byte c2, byte c3) { + c1 = _s1[i1]; + c2 = intern(_s1, i2); + c3 = internIndirect(_s1)[i3]; + } + function intern(bytes memory _s1, uint i) public returns (byte c) { + return _s1[i]; } - function g() public returns (uint, uint) { - // Previous implementation "moved" b to the second place and did not skip. - (uint a,, uint b) = this.f(); - return (a, b); + function internIndirect(bytes memory _s1) public returns (bytes memory) { + return _s1; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(7), u256(8))); + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + bytes args1 = encodeArgs(u256(0x80), u256(3), u256(4), u256(5)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(bytes,uint256,uint256,uint256)", asString(args1)) == + encodeArgs(string{s1[3]}, string{s1[4]}, string{s1[5]}) + ); } -BOOST_AUTO_TEST_CASE(skip_dynamic_types_for_structs) +BOOST_AUTO_TEST_CASE(bytes_in_constructors_unpacker) { - // For accessors, the dynamic types are already removed in the external signature itself. char const* sourceCode = R"( - contract C { - struct S { - uint x; - string a; // this is present in the accessor - uint[] b; // this is not present - uint y; - } - S public s; - function g() public returns (uint, uint) { - s.x = 2; - s.a = "abc"; - s.b = [7, 8, 9]; - s.y = 6; - (uint x,, uint y) = this.s(); - return (x, y); + contract Test { + uint public m_x; + bytes public m_s; + constructor(uint x, bytes memory s) public { + m_x = x; + m_s = s; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(2), u256(6))); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + compileAndRun(sourceCode, 0, "Test", args1); + BOOST_REQUIRE(callContractFunction("m_x()") == encodeArgs(x)); + BOOST_REQUIRE(callContractFunction("m_s()") == encodeArgs(u256(0x20)) + dyn1); } -BOOST_AUTO_TEST_CASE(failed_create) +BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer) { char const* sourceCode = R"( - contract D { constructor() public payable {} } - contract C { - uint public x; - constructor() public payable {} - function f(uint amount) public returns (D) { - x++; - return (new D).value(amount)(); + contract Base { + uint public m_x; + bytes m_s; + constructor(uint x, bytes memory s) public { + m_x = x; + m_s = s; } - function stack(uint depth) public returns (address) { - if (depth < 1024) - return this.stack(depth - 1); - else - return address(f(0)); + function part(uint i) public returns (byte) { + return m_s[i]; + } + } + contract Main is Base { + constructor(bytes memory s, uint x) Base(x, f(s)) public {} + function f(bytes memory s) public returns (bytes memory) { + return s; + } + } + contract Creator { + function f(uint x, bytes memory s) public returns (uint r, byte ch) { + Main c = new Main(s, x); + r = c.m_x(); + ch = c.part(x); } } )"; - compileAndRun(sourceCode, 20, "C"); - BOOST_CHECK(callContractFunction("f(uint256)", 20) != encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("f(uint256)", 20), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("stack(uint256)", 1023), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); + compileAndRun(sourceCode, 0, "Creator"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(uint256,bytes)", asString(args1)) == + encodeArgs(x, string{s1[unsigned(x)]}) + ); } -BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length) +BOOST_AUTO_TEST_CASE(arrays_in_constructors) { char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint[][] memory a = new uint[][](0); - return 7; + contract Base { + uint public m_x; + address[] m_s; + constructor(uint x, address[] memory s) public { + m_x = x; + m_s = s; + } + function part(uint i) public returns (address) { + return m_s[i]; } } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor) -{ - // Memory arrays are initialized using calldatacopy past the size of the calldata. - // This test checks that it also works in the constructor context. - char const* sourceCode = R"( - contract C { - bool public success; - constructor() public { - // Make memory dirty. - assembly { - for { let i := 0 } lt(i, 64) { i := add(i, 1) } { - mstore(msize(), not(0)) - } - } - uint16[3] memory c; - require(c[0] == 0 && c[1] == 0 && c[2] == 0); - uint16[] memory x = new uint16[](3); - require(x[0] == 0 && x[1] == 0 && x[2] == 0); - success = true; + contract Main is Base { + constructor(address[] memory s, uint x) Base(x, f(s)) public {} + function f(address[] memory s) public returns (address[] memory) { + return s; + } + } + contract Creator { + function f(uint x, address[] memory s) public returns (uint r, address ch) { + Main c = new Main(s, x); + r = c.m_x(); + ch = c.part(x); } } )"; - // Cannot run against yul optimizer because of msize - if (!m_optimiserSettings.runYulOptimiser) - { - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("success()"), encodeArgs(u256(1))); - } + compileAndRun(sourceCode, 0, "Creator"); + vector s1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + bytes dyn1 = encodeArgs(u256(s1.size()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(uint256,address[])", asString(args1)) == + encodeArgs(x, s1[unsigned(x)]) + ); } -BOOST_AUTO_TEST_CASE(return_does_not_skip_modifier) +BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) { char const* sourceCode = R"( - contract C { - uint public x; - modifier setsx { - _; - x = 9; + contract Test { + uint24[] public data; + function set(uint24[] memory _data) public returns (uint) { + data = _data; + return data.length; } - function f() setsx public returns (uint) { - return 2; + function get() public returns (uint24[] memory) { + return data; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(9))); + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[])", u256(0x20), u256(data.size()), data) == + encodeArgs(u256(data.size())) + ); + ABI_CHECK(callContractFunction("data(uint256)", u256(7)), encodeArgs(u256(8))); + ABI_CHECK(callContractFunction("data(uint256)", u256(15)), encodeArgs(u256(16))); + ABI_CHECK(callContractFunction("data(uint256)", u256(18)), encodeArgs()); + ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size()), data)); } -BOOST_AUTO_TEST_CASE(break_in_modifier) +BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) { char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - _; - break; - } + contract Test { + uint24[3][] public data; + function set(uint24[3][] memory _data) public returns (uint) { + data = _data; + return data.length; } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; + function get() public returns (uint24[3][] memory) { + return data; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == + encodeArgs(u256(data.size() / 3)) + ); + ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)), encodeArgs(u256(9))); + ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)), encodeArgs(u256(17))); + ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)), encodeArgs()); + ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size() / 3), data)); } -BOOST_AUTO_TEST_CASE(continue_in_modifier) +BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) { char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - if (i % 2 == 1) continue; - _; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; + contract Test { + function set(uint24[3][] memory _data, uint a, uint b) public returns (uint l, uint e) { + l = _data.length; + e = _data[a][b]; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(5))); + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + ALSO_VIA_YUL( + compileAndRun(sourceCode, 0, "Test"); + + BOOST_REQUIRE(callContractFunction( + "set(uint24[3][],uint256,uint256)", + u256(0x60), + u256(3), + u256(2), + u256(data.size() / 3), + data + ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); + ); } -BOOST_AUTO_TEST_CASE(return_in_modifier) +BOOST_AUTO_TEST_CASE(bytes_memory_index_access) { char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 1; i < 10; i++) { - if (i == 5) return; - _; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; + contract Test { + function set(bytes memory _data, uint i) public returns (uint l, byte c) { + l = _data.length; + c = _data[i]; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(4))); + string data("abcdefgh"); + + ALSO_VIA_YUL( + compileAndRun(sourceCode, 0, "Test"); + + BOOST_REQUIRE(callContractFunction( + "set(bytes,uint256)", + u256(0x40), + u256(3), + u256(data.size()), + data + ) == encodeArgs(u256(data.size()), string("d"))); + ); } -BOOST_AUTO_TEST_CASE(stacked_return_with_modifiers) +BOOST_AUTO_TEST_CASE(memory_types_initialisation) { char const* sourceCode = R"( - contract C { - uint public x; - modifier run() { - for (uint i = 0; i < 10; i++) { - _; - break; - } - } - function f() run public { - uint k = x; - uint t = k + 1; - x = t; + contract Test { + mapping(uint=>uint) data; + function stat() public returns (uint[5] memory) + { + data[2] = 3; // make sure to use some memory } + function dyn() public returns (uint[] memory) { stat(); } + function nested() public returns (uint[3][] memory) { stat(); } + function nestedStat() public returns (uint[3][7] memory) { stat(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); + compileAndRun(sourceCode, 0, "Test"); + + ABI_CHECK(callContractFunction("stat()"), encodeArgs(vector(5))); + ABI_CHECK(callContractFunction("dyn()"), encodeArgs(u256(0x20), u256(0))); + ABI_CHECK(callContractFunction("nested()"), encodeArgs(u256(0x20), u256(0))); + ABI_CHECK(callContractFunction("nestedStat()"), encodeArgs(vector(3 * 7))); } -BOOST_AUTO_TEST_CASE(mutex) +BOOST_AUTO_TEST_CASE(memory_arrays_delete) { - char const* sourceCode = R"( - contract mutexed { - bool locked; - modifier protected { - if (locked) revert(); - locked = true; - _; - locked = false; - } - } - contract Fund is mutexed { - uint shares; - constructor() public payable { shares = msg.value; } - function withdraw(uint amount) public protected returns (uint) { - // NOTE: It is very bad practice to write this function this way. - // Please refer to the documentation of how to do this properly. - if (amount > shares) revert(); - (bool success,) = msg.sender.call.value(amount)(""); - require(success); - shares -= amount; - return shares; - } - function withdrawUnprotected(uint amount) public returns (uint) { - // NOTE: It is very bad practice to write this function this way. - // Please refer to the documentation of how to do this properly. - if (amount > shares) revert(); - (bool success,) = msg.sender.call.value(amount)(""); - require(success); - shares -= amount; - return shares; - } - } - contract Attacker { - Fund public fund; - uint callDepth; - bool protected; - function setProtected(bool _protected) public { protected = _protected; } - constructor(Fund _fund) public { fund = _fund; } - function attack() public returns (uint) { - callDepth = 0; - return attackInternal(); - } - function attackInternal() internal returns (uint) { - if (protected) - return fund.withdraw(10); - else - return fund.withdrawUnprotected(10); - } - fallback() external payable { - callDepth++; - if (callDepth < 4) - attackInternal(); + char const* sourceCode = R"( + contract Test { + function del() public returns (uint24[3][4] memory) { + uint24[3][4] memory x; + for (uint24 i = 0; i < x.length; i ++) + for (uint24 j = 0; j < x[i].length; j ++) + x[i][j] = i * 0x10 + j; + delete x[1]; + delete x[3][2]; + return x; } } )"; - compileAndRun(sourceCode, 500, "Fund"); - auto fund = m_contractAddress; - BOOST_CHECK_EQUAL(balanceAt(fund), 500); - compileAndRun(sourceCode, 0, "Attacker", encodeArgs(u160(fund))); - ABI_CHECK(callContractFunction("setProtected(bool)", true), encodeArgs()); - ABI_CHECK(callContractFunction("attack()"), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(fund), 500); - ABI_CHECK(callContractFunction("setProtected(bool)", false), encodeArgs()); - ABI_CHECK(callContractFunction("attack()"), encodeArgs(u256(460))); - BOOST_CHECK_EQUAL(balanceAt(fund), 460); + compileAndRun(sourceCode, 0, "Test"); + + vector data(3 * 4); + for (unsigned i = 0; i < 4; i++) + for (unsigned j = 0; j < 3; j++) + { + u256 v = 0; + if (!(i == 1 || (i == 3 && j == 2))) + v = i * 0x10 + j; + data[i * 3 + j] = v; + } + ABI_CHECK(callContractFunction("del()"), encodeArgs(data)); } -BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws) +BOOST_AUTO_TEST_CASE(memory_arrays_index_access_write) { - char const* sourceCode = R"YY( - abstract contract D { function g() public virtual; } - contract C { - D d = D(0x1212); - function f() public returns (uint) { - d.g(); - return 7; - } - function g() public returns (uint) { - d.g.gas(200)(); - return 7; + char const* sourceCode = R"( + contract Test { + function set(uint24[3][4] memory x) public { + x[2][2] = 1; + x[3][2] = 7; } - function h() public returns (uint) { - address(d).call(""); // this does not throw (low-level) - return 7; + function f() public returns (uint24[3][4] memory){ + uint24[3][4] memory data; + set(data); + return data; } } - )YY"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(7))); + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data(3 * 4); + data[3 * 2 + 2] = 1; + data[3 * 3 + 2] = 7; + ABI_CHECK(callContractFunction("f()"), encodeArgs(data)); } -BOOST_AUTO_TEST_CASE(payable_constructor) +BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) { char const* sourceCode = R"( - contract C { - constructor() public payable { } + contract Test { + uint24[3][][4] data; + function set(uint24[3][][4] memory x) internal returns (uint24[3][][4] memory) { + x[1][2][2] = 1; + x[1][3][2] = 7; + return x; + } + function f() public returns (uint24[3][] memory) { + while (data[1].length < 4) + data[1].push(); + return set(data)[1]; + } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 27, "C"); - ) + compileAndRun(sourceCode, 0, "Test"); + + vector data(3 * 4); + data[3 * 2 + 2] = 1; + data[3 * 3 + 2] = 7; + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x20), u256(4), data)); } -BOOST_AUTO_TEST_CASE(payable_function) +BOOST_AUTO_TEST_CASE(memory_structs_nested_load) { char const* sourceCode = R"( - contract C { - uint public a; - function f() payable public returns (uint) { - return msg.value; + contract Test { + struct S { uint8 x; uint16 y; uint z; } + struct X { uint8 x; S s; uint8[2] a; } + X m_x; + function load() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { + m_x.x = 1; + m_x.s.x = 2; + m_x.s.y = 3; + m_x.s.z = 4; + m_x.a[0] = 5; + m_x.a[1] = 6; + X memory d = m_x; + a = d.x; + x = d.s.x; + y = d.s.y; + z = d.s.z; + a1 = d.a[0]; + a2 = d.a[1]; } - fallback() external payable { - a = msg.value + 1; + function store() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { + X memory d; + d.x = 1; + d.s.x = 2; + d.s.y = 3; + d.s.z = 4; + d.a[0] = 5; + d.a[1] = 6; + m_x = d; + a = m_x.x; + x = m_x.s.x; + y = m_x.s.y; + z = m_x.s.z; + a1 = m_x.a[0]; + a2 = m_x.a[1]; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(27))); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27); - ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(28))); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); + compileAndRun(sourceCode, 0, "Test"); + + auto out = encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5), u256(6)); + ABI_CHECK(callContractFunction("load()"), out); + ABI_CHECK(callContractFunction("store()"), out); } -BOOST_AUTO_TEST_CASE(payable_function_calls_library) +BOOST_AUTO_TEST_CASE(struct_constructor_nested) { char const* sourceCode = R"( - library L { - function f() public returns (uint) { return 7; } - } contract C { - function f() public payable returns (uint) { - return L.f(); + struct X { uint x1; uint x2; } + struct S { uint s1; uint[3] s2; X s3; } + S s; + constructor() public { + uint[3] memory s2; + s2[1] = 9; + s = S(1, s2, X(4, 5)); + } + function get() public returns (uint s1, uint[3] memory s2, uint x1, uint x2) + { + s1 = s.s1; + s2 = s.s2; + x1 = s.s3.x1; + x2 = s.s3.x2; } } )"; - compileAndRun(sourceCode, 0, "L"); - compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); - ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(7))); + compileAndRun(sourceCode, 0, "C"); + + auto out = encodeArgs(u256(1), u256(0), u256(9), u256(0), u256(4), u256(5)); + ABI_CHECK(callContractFunction("get()"), out); } -BOOST_AUTO_TEST_CASE(non_payable_throw) +BOOST_AUTO_TEST_CASE(calldata_struct_short) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - uint public a; - function f() public returns (uint) { - return msgvalue(); - } - function msgvalue() internal returns (uint) { - return msg.value; - } - fallback() external { - update(); - } - function update() internal { - a = msg.value + 1; + struct S { uint256 a; uint256 b; } + function f(S calldata) external pure returns (uint256) { + return msg.data.length; } - } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); - ABI_CHECK(callContractFunction(""), encodeArgs()); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunctionWithValue("a()", 27), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); + + // double check that the valid case goes through + ABI_CHECK(callContractFunction("f((uint256,uint256))", u256(1), u256(2)), encodeArgs(0x44)); + + ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(63,0)), encodeArgs()); + ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(33,0)), encodeArgs()); + ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(32,0)), encodeArgs()); + ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes(31,0)), encodeArgs()); + ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes()), encodeArgs()); } -BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier) +BOOST_AUTO_TEST_CASE(calldata_struct_cleaning) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - modifier tryCircumvent { - if (false) _; // avoid the function, we should still not accept ether - } - function f() tryCircumvent public returns (uint) { - return msgvalue(); - } - function msgvalue() internal returns (uint) { - return msg.value; + struct S { uint8 a; bytes1 b; } + function f(S calldata s) external pure returns (uint256 a, bytes32 b) { + uint8 tmp1 = s.a; + bytes1 tmp2 = s.b; + assembly { + a := tmp1 + b := tmp2 + } + } } )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs()); - BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); - ) + compileAndRun(sourceCode, 0, "C"); + + // double check that the valid case goes through + ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x12), bytes{0x34} + bytes(31,0)), encodeArgs(0x12, bytes{0x34} + bytes(31,0))); + ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x1234), bytes{0x56, 0x78} + bytes(30,0)), encodeArgs()); + ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(-1), u256(-1)), encodeArgs()); } -BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) +BOOST_AUTO_TEST_CASE(calldata_struct_function_type) { - // This tests that memory resize for return values is not paid during the call, which would - // make the gas calculation overly complex. We access the end of the output area before - // the call is made. - // Tests that this also survives the optimizer. char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - function f() public returns (uint[200] memory) {} - } - contract D { - function f(C c) public returns (uint) { c.f(); return 7; } + struct S { function (uint) external returns (uint) fn; } + function f(S calldata s) external returns (uint256) { + return s.fn(42); + } + function g(uint256 a) external returns (uint256) { + return a * 3; + } + function h(uint256 a) external returns (uint256) { + return 23; + } } )"; - compileAndRun(sourceCode, 0, "C"); - u160 cAddr = m_contractAddress; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f(address)", cAddr), encodeArgs(u256(7))); + + bytes fn_C_g = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + bytes(8,0); + bytes fn_C_h = m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("h(uint256)")).asBytes() + bytes(8,0); + ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_g), encodeArgs(42 * 3)); + ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_h), encodeArgs(23)); } -BOOST_AUTO_TEST_CASE(calling_uninitialized_function) +BOOST_AUTO_TEST_CASE(calldata_array_dynamic_bytes) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - function intern() public returns (uint) { - function (uint) internal returns (uint) x; - x(2); - return 7; + function f1(bytes[1] calldata a) external returns (uint256, uint256, uint256, uint256) { + return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2])); } - function extern() public returns (uint) { - function (uint) external returns (uint) x; - x(2); - return 7; + function f2(bytes[1] calldata a, bytes[1] calldata b) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256) { + return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), b[0].length, uint8(b[0][0]), uint8(b[0][1])); + } + function g1(bytes[2] calldata a) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) { + return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])); + } + function g2(bytes[] calldata a) external returns (uint256[8] memory) { + return [a.length, a[0].length, uint8(a[0][0]), uint8(a[0][1]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])]; } } )"; - compileAndRun(sourceCode, 0, "C"); - // This should throw exceptions - ABI_CHECK(callContractFunction("intern()"), encodeArgs()); - ABI_CHECK(callContractFunction("extern()"), encodeArgs()); + + bytes bytes010203 = bytes{1,2,3}+bytes(29,0); + bytes bytes040506 = bytes{4,5,6}+bytes(29,0); + bytes bytes0102 = bytes{1,2}+bytes(30,0); + ABI_CHECK( + callContractFunction("f1(bytes[1])", 0x20, 0x20, 3, bytes010203), + encodeArgs(3, 1, 2, 3) + ); + ABI_CHECK( + callContractFunction("f2(bytes[1],bytes[1])", 0x40, 0xA0, 0x20, 3, bytes010203, 0x20, 2, bytes0102), + encodeArgs(3, 1, 2, 3, 2, 1, 2) + ); + ABI_CHECK( + callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x80, 3, bytes010203, 3, bytes040506), + encodeArgs(3, 1, 2, 3, 3, 4, 5, 6) + ); + // same offset for both arrays + ABI_CHECK( + callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x40, 3, bytes010203), + encodeArgs(3, 1, 2, 3, 3, 1, 2, 3) + ); + ABI_CHECK( + callContractFunction("g2(bytes[])", 0x20, 2, 0x40, 0x80, 2, bytes0102, 3, bytes040506), + encodeArgs(2, 2, 1, 2, 3, 4, 5, 6) + ); } -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail) +BOOST_AUTO_TEST_CASE(calldata_bytes_array_to_memory) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - function() internal returns (uint) x; - int mutex; - function t() public returns (uint) { - if (mutex > 0) - { assembly { mstore(0, 7) return(0, 0x20) } } - mutex = 1; - // Avoid re-executing this function if we jump somewhere. - x(); - return 2; + function f(bytes[] calldata a) external returns (uint, uint, bytes memory) { + bytes memory m = a[0]; + return (a.length, m.length, m); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); + + ABI_CHECK( + callContractFunction("f(bytes[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs(1, 2, 0x60, 2, bytes{'a','b'} + bytes(30, 0)) + ); + + ABI_CHECK( + callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, bytes(32, 'x')), + encodeArgs(1, 32, 0x60, 32, bytes(32, 'x')) + ); + bytes x_zero_a = bytes{'x'} + bytes(30, 0) + bytes{'a'}; + bytes a_zero_x = bytes{'a'} + bytes(30, 0) + bytes{'x'}; + bytes a_m_x = bytes{'a'} + bytes(30, 'm') + bytes{'x'}; + ABI_CHECK( + callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, x_zero_a), + encodeArgs(1, 32, 0x60, 32, x_zero_a) + ); + ABI_CHECK( + callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_zero_x), + encodeArgs(1, 32, 0x60, 32, a_zero_x) + ); + ABI_CHECK( + callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_m_x), + encodeArgs(1, 32, 0x60, 32, a_m_x) + ); } -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_through_array) +BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - int mutex; - function t() public returns (uint) { - if (mutex > 0) - { assembly { mstore(0, 7) return(0, 0x20) } } - mutex = 1; - // Avoid re-executing this function if we jump somewhere. - function() internal returns (uint)[200] memory x; - x[0](); - return 2; + function f(bytes[] calldata a, uint256 i) external returns (uint) { + return uint8(a[0][i]); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); + + ABI_CHECK( + callContractFunction("f(bytes[],uint256)", 0x40, 0, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs('a') + ); + ABI_CHECK( + callContractFunction("f(bytes[],uint256)", 0x40, 1, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs('b') + ); + ABI_CHECK( + callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs() + ); } -BOOST_AUTO_TEST_CASE(pass_function_types_internally) +BOOST_AUTO_TEST_CASE(calldata_string_array) { char const* sourceCode = R"( + pragma experimental ABIEncoderV2; contract C { - function f(uint x) public returns (uint) { - return eval(g, x); - } - function eval(function(uint) internal returns (uint) x, uint a) internal returns (uint) { - return x(a); + function f(string[] calldata a) external returns (uint, uint, uint, string memory) { + string memory s1 = a[0]; + bytes memory m1 = bytes(s1); + return (a.length, m1.length, uint8(m1[0]), s1); } - function g(uint x) public returns (uint) { return x + 1; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", 7), encodeArgs(u256(8))); + + ABI_CHECK( + callContractFunction("f(string[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs(1, 2, 'a', 0x80, 2, bytes{'a', 'b'} + bytes(30, 0)) + ); } -BOOST_AUTO_TEST_CASE(pass_function_types_externally) +BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) { - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint) { - return this.eval(this.g, x); - } - function f2(uint x) public returns (uint) { - return eval(this.g, x); + vector> data { + { 0x0A01, 0x0A02, 0x0A03 }, + { 0x0B01, 0x0B02, 0x0B03, 0x0B04 } + }; + + for (bool outerDynamicallySized: { true, false }) + { + string arrayType = outerDynamicallySized ? "uint256[][]" : "uint256[][2]"; + string sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + function test()" + arrayType + R"( calldata a) external returns (uint256) { + return a.length; + } + function test()" + arrayType + R"( calldata a, uint256 i) external returns (uint256) { + return a[i].length; + } + function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { + return a[i][j]; + } + function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { + return this.test(a, i, j); + } } - function eval(function(uint) external returns (uint) x, uint a) public returns (uint) { - return x(a); + )"; + compileAndRun(sourceCode, 0, "C"); + + bytes encoding = encodeArray( + outerDynamicallySized, + true, + data | boost::adaptors::transformed([&](vector const& _values) { + return encodeArray(true, false, _values); + }) + ); + + ABI_CHECK(callContractFunction("test(" + arrayType + ")", 0x20, encoding), encodeArgs(data.size())); + for (size_t i = 0; i < data.size(); i++) + { + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size())); + for (size_t j = 0; j < data[i].size(); j++) + { + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); + ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); } - function g(uint x) public returns (uint) { return x + 1; } + // out of bounds access + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs()); } - )"; + // out of bounds access + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs()); + } +} - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", 7), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("f2(uint256)", 7), encodeArgs(u256(8))); +BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) +{ + vector>> data { + { + { 0x010A01, 0x010A02, 0x010A03 }, + { 0x010B01, 0x010B02, 0x010B03 } + }, + { + { 0x020A01, 0x020A02, 0x020A03 }, + { 0x020B01, 0x020B02, 0x020B03 } + } + }; + + for (bool outerDynamicallySized: { true, false }) + for (bool middleDynamicallySized: { true, false }) + for (bool innerDynamicallySized: { true, false }) + { + // only test dynamically encoded arrays + if (!outerDynamicallySized && !middleDynamicallySized && !innerDynamicallySized) + continue; + + string arrayType = "uint256"; + arrayType += innerDynamicallySized ? "[]" : "[3]"; + arrayType += middleDynamicallySized ? "[]" : "[2]"; + arrayType += outerDynamicallySized ? "[]" : "[2]"; + + string sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + function test()" + arrayType + R"( calldata a) external returns (uint256) { + return a.length; + } + function test()" + arrayType + R"( calldata a, uint256 i) external returns (uint256) { + return a[i].length; + } + function test()" + arrayType + R"( calldata a, uint256 i, uint256 j) external returns (uint256) { + return a[i][j].length; + } + function test()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { + return a[i][j][k]; + } + function reenc()" + arrayType + R"( calldata a, uint256 i, uint256 j, uint256 k) external returns (uint256) { + return this.test(a, i, j, k); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + + bytes encoding = encodeArray( + outerDynamicallySized, + middleDynamicallySized || innerDynamicallySized, + data | boost::adaptors::transformed([&](auto const& _middleData) { + return encodeArray( + middleDynamicallySized, + innerDynamicallySized, + _middleData | boost::adaptors::transformed([&](auto const& _values) { + return encodeArray(innerDynamicallySized, false, _values); + }) + ); + }) + ); + + ABI_CHECK(callContractFunction("test(" + arrayType + ")", 0x20, encoding), encodeArgs(data.size())); + for (size_t i = 0; i < data.size(); i++) + { + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, i, encoding), encodeArgs(data[i].size())); + for (size_t j = 0; j < data[i].size(); j++) + { + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j].size())); + for (size_t k = 0; k < data[i][j].size(); k++) + { + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); + ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); + } + // out of bounds access + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), encodeArgs()); + } + // out of bounds access + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs()); + } + // out of bounds access + ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs()); + } } -BOOST_AUTO_TEST_CASE(receive_external_function_type) +BOOST_AUTO_TEST_CASE(literal_strings) { char const* sourceCode = R"( - contract C { - function g() public returns (uint) { return 7; } - function f(function() external returns (uint) g) public returns (uint) { - return g(); + contract Test { + string public long; + string public medium; + string public short; + string public empty; + function f() public returns (string memory) { + long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; + short = "123"; + empty = ""; + return "Hello, World!"; } } )"; + compileAndRun(sourceCode, 0, "Test"); + string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + string medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; + string shortStr = "123"; + string hello = "Hello, World!"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction( - "f(function)", - m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) - ), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("f()"), encodeDyn(hello)); + ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr)); + ABI_CHECK(callContractFunction("medium()"), encodeDyn(medium)); + ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); + ABI_CHECK(callContractFunction("empty()"), encodeDyn(string())); } -BOOST_AUTO_TEST_CASE(return_external_function_type) +BOOST_AUTO_TEST_CASE(initialise_string_constant) { char const* sourceCode = R"( - contract C { - function g() public {} - function f() public returns (function() external) { - return this.g; - } + contract Test { + string public short = "abcdef"; + string public long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; } )"; + compileAndRun(sourceCode, 0, "Test"); + string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; + string shortStr = "abcdef"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK( - callContractFunction("f()"), - m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) - ); + ABI_CHECK(callContractFunction("long()"), encodeDyn(longStr)); + ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); } -BOOST_AUTO_TEST_CASE(store_function) +BOOST_AUTO_TEST_CASE(string_bytes_conversion) { char const* sourceCode = R"( - contract Other { - function addTwo(uint x) public returns (uint) { return x + 2; } - } - contract C { - function (function (uint) external returns (uint)) internal returns (uint) ev; - function (uint) external returns (uint) x; - function store(function(uint) external returns (uint) y) public { - x = y; - } - function eval(function(uint) external returns (uint) y) public returns (uint) { - return y(7); - } - function t() public returns (uint) { - ev = eval; - this.store((new Other()).addTwo); - return ev(x); + contract Test { + string s; + bytes b; + function f(string memory _s, uint n) public returns (byte) { + b = bytes(_s); + s = string(b); + return bytes(s)[n]; } + function l() public returns (uint) { return bytes(s).length; } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(9))); + compileAndRun(sourceCode, 0, "Test"); + ABI_CHECK(callContractFunction("f(string,uint256)", u256(0x40), u256(2), u256(6), string("abcdef")), encodeArgs("c")); + ABI_CHECK(callContractFunction("l()"), encodeArgs(u256(6))); } -BOOST_AUTO_TEST_CASE(store_function_in_constructor) +BOOST_AUTO_TEST_CASE(string_as_mapping_key) { char const* sourceCode = R"( - contract C { - uint public result_in_constructor; - function (uint) internal returns (uint) x; - constructor() public { - x = double; - result_in_constructor = use(2); - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - function use(uint _arg) public returns (uint) { - return x(_arg); - } + contract Test { + mapping(string => uint) data; + function set(string memory _s, uint _v) public { data[_s] = _v; } + function get(string memory _s) public returns (uint) { return data[_s]; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("result_in_constructor()"), encodeArgs(u256(4))); -} + vector strings{ + "Hello, World!", + "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", + "", + "1" + }; -// TODO: store bound internal library functions + ALSO_VIA_YUL( + compileAndRun(sourceCode, 0, "Test"); + for (unsigned i = 0; i < strings.size(); i++) + ABI_CHECK(callContractFunction( + "set(string,uint256)", + u256(0x40), + u256(7 + i), + u256(strings[i].size()), + strings[i] + ), encodeArgs()); + for (unsigned i = 0; i < strings.size(); i++) + ABI_CHECK(callContractFunction( + "get(string)", + u256(0x20), + u256(strings[i].size()), + strings[i] + ), encodeArgs(u256(7 + i))); + ) +} -BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor) +BOOST_AUTO_TEST_CASE(string_as_public_mapping_key) { char const* sourceCode = R"( - contract C { - function () internal returns (uint) x; - constructor() public { - x = unused; - } - function unused() internal returns (uint) { - return 7; - } - function t() public returns (uint) { - return x(); - } + contract Test { + mapping(string => uint) public data; + function set(string memory _s, uint _v) public { data[_s] = _v; } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); + compileAndRun(sourceCode, 0, "Test"); + vector strings{ + "Hello, World!", + "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", + "", + "1" + }; + for (unsigned i = 0; i < strings.size(); i++) + ABI_CHECK(callContractFunction( + "set(string,uint256)", + u256(0x40), + u256(7 + i), + u256(strings[i].size()), + strings[i] + ), encodeArgs()); + for (unsigned i = 0; i < strings.size(); i++) + ABI_CHECK(callContractFunction( + "data(string)", + u256(0x20), + u256(strings[i].size()), + strings[i] + ), encodeArgs(u256(7 + i))); } -BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor) +BOOST_AUTO_TEST_CASE(nested_string_as_public_mapping_key) { char const* sourceCode = R"( - library L { function x() internal returns (uint) { return 7; } } - contract C { - function () internal returns (uint) x; - constructor() public { - x = L.x; - } - function t() public returns (uint) { - return x(); - } + contract Test { + mapping(string => mapping(string => uint)) public data; + function set(string memory _s, string memory _s2, uint _v) public { + data[_s][_s2] = _v; } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); + compileAndRun(sourceCode, 0, "Test"); + vector strings{ + "Hello, World!", + "Hello, World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111", + "", + "1", + "last one" + }; + for (unsigned i = 0; i + 1 < strings.size(); i++) + ABI_CHECK(callContractFunction( + "set(string,string,uint256)", + u256(0x60), + u256(roundTo32(0x80 + strings[i].size())), + u256(7 + i), + u256(strings[i].size()), + strings[i], + u256(strings[i+1].size()), + strings[i+1] + ), encodeArgs()); + for (unsigned i = 0; i + 1 < strings.size(); i++) + ABI_CHECK(callContractFunction( + "data(string,string)", + u256(0x40), + u256(roundTo32(0x60 + strings[i].size())), + u256(strings[i].size()), + strings[i], + u256(strings[i+1].size()), + strings[i+1] + ), encodeArgs(u256(7 + i))); } -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime) +BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key) { char const* sourceCode = R"( - contract C { - uint public initial; - constructor() public { - initial = double(2); - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - function runtime(uint _arg) public returns (uint) { - return double(_arg); + contract Test { + mapping(string => + mapping(int => + mapping(address => + mapping(bytes => int)))) public data; + + function set( + string memory _s1, + int _s2, + address _s3, + bytes memory _s4, + int _value + ) public + { + data[_s1][_s2][_s3][_s4] = _value; } } )"; + compileAndRun(sourceCode, 0, "Test"); - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("initial()"), encodeArgs(u256(4))); + struct Index + { + string s1; + int s2; + int s3; + string s4; + }; + + vector data{ + { "aabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcbc", 4, 23, "efg" }, + { "tiaron", 456, 63245, "908apzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapzapz" }, + { "", 2345, 12934, "665i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i65i5iart" }, + { "¡¿…", 9781, 8148, "" }, + { "ρν♀♀ω₂₃♀", 929608, 303030, "" } + }; + + for (size_t i = 0; i + 1 < data.size(); i++) + ABI_CHECK(callContractFunction( + "set(string,int256,address,bytes,int256)", + u256(0xA0), + u256(data[i].s2), + u256(data[i].s3), + u256(roundTo32(0xC0 + data[i].s1.size())), + u256(i - 3), + u256(data[i].s1.size()), + data[i].s1, + u256(data[i].s4.size()), + data[i].s4 + ), encodeArgs()); + for (size_t i = 0; i + 1 < data.size(); i++) + ABI_CHECK(callContractFunction( + "data(string,int256,address,bytes)", + u256(0x80), + u256(data[i].s2), + u256(data[i].s3), + u256(roundTo32(0xA0 + data[i].s1.size())), + u256(data[i].s1.size()), + data[i].s1, + u256(data[i].s4.size()), + data[i].s4 + ), encodeArgs(u256(i - 3))); } -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check) +BOOST_AUTO_TEST_CASE(constant_string_literal) { char const* sourceCode = R"( - contract C { - function (uint) internal returns (uint) x; + contract Test { + bytes32 constant public b = "abcdefghijklmnopq"; + string constant public x = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca"; + constructor() public { - x = double; - } - function test() public returns (bool) { - return x == double; + string memory xx = x; + bytes32 bb = b; } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; + function getB() public returns (bytes32) { return b; } + function getX() public returns (string memory) { return x; } + function getX2() public returns (string memory r) { r = x; } + function unused() public returns (uint) { + "unusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunusedunused"; + return 2; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); + compileAndRun(sourceCode); + string longStr = "abefghijklmnopqabcdefghijklmnopqabcdefghijklmnopqabca"; + string shortStr = "abcdefghijklmnopq"; + ABI_CHECK(callContractFunction("b()"), encodeArgs(shortStr)); + ABI_CHECK(callContractFunction("x()"), encodeDyn(longStr)); + ABI_CHECK(callContractFunction("getB()"), encodeArgs(shortStr)); + ABI_CHECK(callContractFunction("getX()"), encodeDyn(longStr)); + ABI_CHECK(callContractFunction("getX2()"), encodeDyn(longStr)); + ABI_CHECK(callContractFunction("unused()"), encodeArgs(2)); } -BOOST_AUTO_TEST_CASE(function_type_library_internal) +BOOST_AUTO_TEST_CASE(library_call) { char const* sourceCode = R"( - library Utils { - function reduce(uint[] memory array, function(uint, uint) internal returns (uint) f, uint init) internal returns (uint) { - for (uint i = 0; i < array.length; i++) { - init = f(array[i], init); - } - return init; - } - function sum(uint a, uint b) internal returns (uint) { - return a + b; - } - } - contract C { - function f(uint[] memory x) public returns (uint) { - return Utils.reduce(x, Utils.sum, 0); + library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } + contract Test { + function f(uint x) public returns (uint) { + return Lib.m(x, 9); } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)), encodeArgs(u256(11))); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(33) * 9)); } - -BOOST_AUTO_TEST_CASE(call_function_returning_function) +BOOST_AUTO_TEST_CASE(library_function_external) { char const* sourceCode = R"( - contract test { - function f0() public returns (uint) { - return 2; - } - function f1() internal returns (function() internal returns (uint)) { - return f0; - } - function f2() internal returns (function() internal returns (function () internal returns (uint))) { - return f1; - } - function f3() internal returns (function() internal returns (function () internal returns (function () internal returns (uint)))) - { - return f2; - } - function f() public returns (uint) { - function() internal returns(function() internal returns(function() internal returns(function() internal returns(uint)))) x; - x = f3; - return x()()()(); + library Lib { function m(bytes calldata b) external pure returns (byte) { return b[2]; } } + contract Test { + function f(bytes memory b) public pure returns (byte) { + return Lib.m(b); } } )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); - ) + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(bytes)", u256(0x20), u256(5), "abcde"), encodeArgs("c")); } -BOOST_AUTO_TEST_CASE(mapping_of_functions) +BOOST_AUTO_TEST_CASE(library_stray_values) { char const* sourceCode = R"( - contract Flow { - bool public success; - - mapping (address => function () internal) stages; - - function stage0() internal { - stages[msg.sender] = stage1; - } - - function stage1() internal { - stages[msg.sender] = stage2; - } - - function stage2() internal { - success = true; - } - - constructor() public { - stages[msg.sender] = stage0; - } - - function f() public returns (uint) { - stages[msg.sender](); - return 7; + library Lib { function m(uint x, uint y) public returns (uint) { return x * y; } } + contract Test { + function f(uint x) public returns (uint) { + Lib; + Lib.m; + return x + 9; } } )"; - - compileAndRun(sourceCode, 0, "Flow"); - ABI_CHECK(callContractFunction("success()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("success()"), encodeArgs(false)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("success()"), encodeArgs(true)); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(42))); } -BOOST_AUTO_TEST_CASE(packed_functions) +BOOST_AUTO_TEST_CASE(strings_in_struct) { char const* sourceCode = R"( - contract C { - // these should take the same slot - function() internal returns (uint) a; - function() external returns (uint) b; - function() external returns (uint) c; - function() internal returns (uint) d; - uint8 public x; + contract buggystruct { + Buggy public bug; - function set() public { - x = 2; - d = g; - c = this.h; - b = this.h; - a = g; - } - function t1() public returns (uint) { - return a(); + struct Buggy { + uint first; + uint second; + uint third; + string last; } - function t2() public returns (uint) { - return b(); + + constructor() public { + bug = Buggy(10, 20, 30, "asdfghjkl"); } - function t3() public returns (uint) { - return a(); + function getFirst() public returns (uint) + { + return bug.first; } - function t4() public returns (uint) { - return b(); + function getSecond() public returns (uint) + { + return bug.second; } - function g() public returns (uint) { - return 7; + function getThird() public returns (uint) + { + return bug.third; } - function h() public returns (uint) { - return 8; + function getLast() public returns (string memory) + { + return bug.last; } } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("t1()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("t2()"), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("t3()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("t4()"), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(2))); + )"; + compileAndRun(sourceCode); + string s = "asdfghjkl"; + ABI_CHECK(callContractFunction("getFirst()"), encodeArgs(u256(10))); + ABI_CHECK(callContractFunction("getSecond()"), encodeArgs(u256(20))); + ABI_CHECK(callContractFunction("getThird()"), encodeArgs(u256(30))); + ABI_CHECK(callContractFunction("getLast()"), encodeDyn(s)); } -BOOST_AUTO_TEST_CASE(function_memory_array) +BOOST_AUTO_TEST_CASE(internal_types_in_library) { char const* sourceCode = R"( - contract C { - function a(uint x) public returns (uint) { return x + 1; } - function b(uint x) public returns (uint) { return x + 2; } - function c(uint x) public returns (uint) { return x + 3; } - function d(uint x) public returns (uint) { return x + 5; } - function e(uint x) public returns (uint) { return x + 8; } - function test(uint x, uint i) public returns (uint) { - function(uint) internal returns (uint)[] memory arr = - new function(uint) internal returns (uint)[](10); - arr[0] = a; - arr[1] = b; - arr[2] = c; - arr[3] = d; - arr[4] = e; - return arr[i](x); + library Lib { + function find(uint16[] storage _haystack, uint16 _needle) public view returns (uint) + { + for (uint i = 0; i < _haystack.length; ++i) + if (_haystack[i] == _needle) + return i; + return uint(-1); + } + } + contract Test { + mapping(string => uint16[]) data; + function f() public returns (uint a, uint b) + { + while (data["abc"].length < 20) + data["abc"].push(); + data["abc"][4] = 9; + data["abc"][17] = 3; + a = Lib.find(data["abc"], 9); + b = Lib.find(data["abc"], 3); } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)), encodeArgs(u256(11))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)), encodeArgs(u256(12))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)), encodeArgs(u256(13))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)), encodeArgs(u256(15))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)), encodeArgs(u256(18))); - ABI_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)), encodeArgs()); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4), u256(17))); } -BOOST_AUTO_TEST_CASE(function_delete_storage) +BOOST_AUTO_TEST_CASE(mapping_arguments_in_library) { char const* sourceCode = R"( - contract C { - function a() public returns (uint) { return 7; } - function() internal returns (uint) y; - function set() public returns (uint) { - y = a; - return y(); + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) internal + { + m[key] = value; } - function d() public returns (uint) { - delete y; - return 1; + function get(mapping(uint => uint) storage m, uint key) internal view returns (uint) + { + return m[key]; + } + } + contract Test { + mapping(uint => uint) m; + function set(uint256 key, uint256 value) public returns (uint) + { + uint oldValue = Lib.get(m, key); + Lib.set(m, key, value); + return oldValue; } - function ca() public returns (uint) { - return y(); + function get(uint256 key) public view returns (uint) { + return Lib.get(m, key); } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("set()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("ca()"), encodeArgs(u256(7))); - ABI_CHECK(callContractFunction("d()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("ca()"), encodeArgs()); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(42)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(84)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(7)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(84))); + ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(1), u256(21)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(2), u256(42)), encodeArgs(u256(84))); + ABI_CHECK(callContractFunction("set(uint256,uint256)", u256(21), u256(14)), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("get(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(uint256)", u256(1)), encodeArgs(u256(21))); + ABI_CHECK(callContractFunction("get(uint256)", u256(2)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get(uint256)", u256(21)), encodeArgs(u256(14))); } -BOOST_AUTO_TEST_CASE(function_delete_stack) +BOOST_AUTO_TEST_CASE(mapping_returns_in_library) { char const* sourceCode = R"( - contract C { - function a() public returns (uint) { return 7; } - function test() public returns (uint) { - function () returns (uint) y = a; - delete y; - y(); + library Lib { + function choose_mapping(mapping(uint => uint) storage a, mapping(uint => uint) storage b, bool c) internal pure returns(mapping(uint=>uint) storage) + { + return c ? a : b; } } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(copy_function_storage_array) -{ - char const* sourceCode = R"( - contract C { - function() internal returns (uint)[] x; - function() internal returns (uint)[] y; - function test() public returns (uint) { - x = new function() internal returns (uint)[](10); - x[9] = a; - y = x; - return y[9](); + contract Test { + mapping(uint => uint) a; + mapping(uint => uint) b; + function set(bool choice, uint256 key, uint256 value) public returns (uint) + { + mapping(uint => uint) storage m = Lib.choose_mapping(a, b, choice); + uint oldValue = m[key]; + m[key] = value; + return oldValue; } - function a() public returns (uint) { - return 7; + function get(bool choice, uint256 key) public view returns (uint) { + return Lib.choose_mapping(a, b, choice)[key]; + } + function get_a(uint256 key) public view returns (uint) { + return a[key]; + } + function get_b(uint256 key) public view returns (uint) { + return b[key]; } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(7))); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(42)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(84)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(7)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(10)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(11)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(12)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(84))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(84))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(10))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(11))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(12))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(10))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(11))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(12))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(1), u256(21)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(2), u256(42)), encodeArgs(u256(84))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", true, u256(21), u256(14)), encodeArgs(u256(7))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(1), u256(30)), encodeArgs(u256(10))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(2), u256(31)), encodeArgs(u256(11))); + ABI_CHECK(callContractFunction("set(bool,uint256,uint256)", false, u256(21), u256(32)), encodeArgs(u256(12))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(1)), encodeArgs(u256(21))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(2)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get_a(uint256)", u256(21)), encodeArgs(u256(14))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(1)), encodeArgs(u256(21))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(2)), encodeArgs(u256(42))); + ABI_CHECK(callContractFunction("get(bool,uint256)", true, u256(21)), encodeArgs(u256(14))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(1)), encodeArgs(u256(30))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(2)), encodeArgs(u256(31))); + ABI_CHECK(callContractFunction("get_b(uint256)", u256(21)), encodeArgs(u256(32))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(0)), encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(1)), encodeArgs(u256(30))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(2)), encodeArgs(u256(31))); + ABI_CHECK(callContractFunction("get(bool,uint256)", false, u256(21)), encodeArgs(u256(32))); } -BOOST_AUTO_TEST_CASE(function_array_cross_calls) +BOOST_AUTO_TEST_CASE(mapping_returns_in_library_named) { char const* sourceCode = R"( - contract D { - function f(function() external returns (function() external returns (uint))[] memory x) - public returns (function() external returns (uint)[3] memory r) + library Lib { + function f(mapping(uint => uint) storage a, mapping(uint => uint) storage b) internal returns(mapping(uint=>uint) storage r) { - r[0] = x[0](); - r[1] = x[1](); - r[2] = x[2](); + r = a; + r[1] = 42; + r = b; + r[1] = 21; } } - contract C { - function test() public returns (uint, uint, uint) { - function() external returns (function() external returns (uint))[] memory x = - new function() external returns (function() external returns (uint))[](10); - for (uint i = 0; i < x.length; i ++) - x[i] = this.h; - x[0] = this.htwo; - function() external returns (uint)[3] memory y = (new D()).f(x); - return (y[0](), y[1](), y[2]()); - } - function e() public returns (uint) { return 5; } - function f() public returns (uint) { return 6; } - function g() public returns (uint) { return 7; } - uint counter; - function h() public returns (function() external returns (uint)) { - return counter++ == 0 ? this.f : this.g; + contract Test { + mapping(uint => uint) a; + mapping(uint => uint) b; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.f(a, b)[2] = 84; + return (a[0], a[1], a[2], b[0], b[1], b[2]); } - function htwo() public returns (function() external returns (uint)) { - return this.e; + function g() public returns (uint, uint, uint, uint, uint, uint) + { + mapping(uint => uint) storage m = Lib.f(a, b); + m[2] = 17; + return (a[0], a[1], a[2], b[0], b[1], b[2]); } } )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(5), u256(6), u256(7))); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(84))); + ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(17))); } -BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage) +BOOST_AUTO_TEST_CASE(using_library_mappings_public) { char const* sourceCode = R"( - contract C { - function() internal returns (uint)[20] x; - int mutex; - function one() public returns (uint) { - function() internal returns (uint)[20] memory xmem; - x = xmem; - return 3; + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) public + { + m[key] = value; + } } - function two() public returns (uint) { - if (mutex > 0) - return 7; - mutex = 1; - // If this test fails, it might re-execute this function. - x[0](); - return 2; + contract Test { + mapping(uint => uint) m1; + mapping(uint => uint) m2; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.set(m1, 0, 1); + Lib.set(m1, 2, 42); + Lib.set(m2, 0, 23); + Lib.set(m2, 2, 99); + return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); + } } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("one()"), encodeArgs(u256(3))); - ABI_CHECK(callContractFunction("two()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(shift_constant_left) -{ - char const* sourceCode = R"( - contract C { - uint public a = 0x42 << 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0x4200))); + )"; + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); } -BOOST_AUTO_TEST_CASE(shift_negative_constant_left) +BOOST_AUTO_TEST_CASE(using_library_mappings_external) { + char const* libSourceCode = R"( + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) external + { + m[key] = value * 2; + } + } + )"; char const* sourceCode = R"( - contract C { - int public a = -0x42 << 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(-0x4200))); + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) external {} + } + contract Test { + mapping(uint => uint) m1; + mapping(uint => uint) m2; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.set(m1, 0, 1); + Lib.set(m1, 2, 42); + Lib.set(m2, 0, 23); + Lib.set(m2, 2, 99); + return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); + } + } + )"; + for (auto v2: {false, true}) + { + string prefix = v2 ? "pragma experimental ABIEncoderV2;\n" : ""; + compileAndRun(prefix + libSourceCode, 0, "Lib"); + compileAndRun(prefix + sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2), u256(0), u256(84), u256(46), u256(0), u256(198))); + } } -BOOST_AUTO_TEST_CASE(shift_constant_right) +BOOST_AUTO_TEST_CASE(using_library_mappings_return) { char const* sourceCode = R"( - contract C { - uint public a = 0x4200 >> 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0x42))); + library Lib { + function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) { + return m[key]; + } + } + contract Test { + mapping(uint => mapping(uint => uint)) m; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.choose(m, 0)[0] = 1; + Lib.choose(m, 0)[2] = 42; + Lib.choose(m, 1)[0] = 23; + Lib.choose(m, 1)[2] = 99; + return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]); + } + } + )"; + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); } -BOOST_AUTO_TEST_CASE(shift_negative_constant_right) +BOOST_AUTO_TEST_CASE(using_library_structs) { char const* sourceCode = R"( - contract C { - int public a = -0x4200 >> 8; + library Lib { + struct Data { uint a; uint[] b; } + function set(Data storage _s) public + { + _s.a = 7; + while (_s.b.length < 20) + _s.b.push(); + _s.b[19] = 8; + } } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(-0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_left) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - return a << b; + contract Test { + mapping(string => Lib.Data) data; + function f() public returns (uint a, uint b) + { + Lib.set(data["abc"]); + a = data["abc"].a; + b = data["abc"].b[19]; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(256)), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), u256(8))); } -BOOST_AUTO_TEST_CASE(shift_left_uint32) +BOOST_AUTO_TEST_CASE(short_strings) { + // This test verifies that the byte array encoding that combines length and data works + // correctly. char const* sourceCode = R"( - contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a << b; + contract A { + bytes public data1 = "123"; + bytes data2; + function lengthChange() public returns (uint) + { + // store constant in short and long string + data1 = "123"; + if (!equal(data1, "123")) return 1; + data2 = "12345678901234567890123456789012345678901234567890a"; + if (data2[17] != "8") return 3; + if (data2.length != 51) return 4; + if (data2[data2.length - 1] != "a") return 5; + // change length: short -> short + while (data1.length < 5) + data1.push(); + if (data1.length != 5) return 6; + data1[4] = "4"; + if (data1[0] != "1") return 7; + if (data1[4] != "4") return 8; + // change length: short -> long + while (data1.length < 80) + data1.push(); + if (data1.length != 80) return 9; + while (data1.length > 70) + data1.pop(); + if (data1.length != 70) return 9; + if (data1[0] != "1") return 10; + if (data1[4] != "4") return 11; + for (uint i = 0; i < data1.length; i ++) + data1[i] = byte(uint8(i * 3)); + if (uint8(data1[4]) != 4 * 3) return 12; + if (uint8(data1[67]) != 67 * 3) return 13; + // change length: long -> short + while (data1.length > 22) + data1.pop(); + if (data1.length != 22) return 14; + if (uint8(data1[21]) != 21 * 3) return 15; + if (uint8(data1[2]) != 2 * 3) return 16; + // change length: short -> shorter + while (data1.length > 19) + data1.pop(); + if (data1.length != 19) return 17; + if (uint8(data1[7]) != 7 * 3) return 18; + // and now again to original size + while (data1.length < 22) + data1.push(); + if (data1.length != 22) return 19; + if (data1[21] != 0) return 20; + while (data1.length > 0) + data1.pop(); + while (data2.length > 0) + data2.pop(); + } + function copy() public returns (uint) { + bytes memory x = "123"; + bytes memory y = "012345678901234567890123456789012345678901234567890123456789"; + bytes memory z = "1234567"; + data1 = x; + data2 = y; + if (!equal(data1, x)) return 1; + if (!equal(data2, y)) return 2; + // lengthen + data1 = y; + if (!equal(data1, y)) return 3; + // shorten + data1 = x; + if (!equal(data1, x)) return 4; + // change while keeping short + data1 = z; + if (!equal(data1, z)) return 5; + // copy storage -> storage + data1 = x; + data2 = y; + // lengthen + data1 = data2; + if (!equal(data1, y)) return 6; + // shorten + data1 = x; + data2 = data1; + if (!equal(data2, x)) return 7; + bytes memory c = data2; + data1 = c; + if (!equal(data1, x)) return 8; + data1 = ""; + data2 = ""; + } + function deleteElements() public returns (uint) { + data1 = "01234"; + delete data1[2]; + if (data1[2] != 0) return 1; + if (data1[0] != "0") return 2; + if (data1[3] != "3") return 3; + delete data1; + if (data1.length != 0) return 4; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(32)), encodeArgs(u256(0))); -} -BOOST_AUTO_TEST_CASE(shift_left_uint8) -{ - char const* sourceCode = R"( - contract C { - function f(uint8 a, uint8 b) public returns (uint) { - return a << b; + function equal(bytes storage a, bytes memory b) internal returns (bool) { + if (a.length != b.length) return false; + for (uint i = 0; i < a.length; ++i) if (a[i] != b[i]) return false; + return true; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(0)), encodeArgs(u256(0x66))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(8)), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "A"); + ABI_CHECK(callContractFunction("data1()"), encodeDyn(string("123"))); + ABI_CHECK(callContractFunction("lengthChange()"), encodeArgs(u256(0))); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("deleteElements()"), encodeArgs(u256(0))); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("copy()"), encodeArgs(u256(0))); + BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(shift_left_larger_type) +BOOST_AUTO_TEST_CASE(calldata_offset) { - // This basically tests proper cleanup and conversion. It should not convert x to int8. + // This tests a specific bug that was caused by not using the correct memory offset in the + // calldata unpacker. char const* sourceCode = R"( - contract C { - function f() public returns (int8) { - uint8 x = 254; - int8 y = 1; - return y << x; + contract CB + { + address[] _arr; + string public last = "nd"; + constructor(address[] memory guardians) public + { + _arr = guardians; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "CB", encodeArgs(u256(0x20), u256(0x00))); + ABI_CHECK(callContractFunction("last()", encodeArgs()), encodeDyn(string("nd"))); } -BOOST_AUTO_TEST_CASE(shift_left_assignment) +BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) { char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - a <<= b; - return a; + library lib {} + contract c { + constructor() public payable {} + function f(address payable x) public returns (bool) { + return x.send(1); } + receive () external payable {} } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(256)), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "lib"); + Address libraryAddress = m_contractAddress; + compileAndRun(sourceCode, 10, "c"); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); + BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); + ABI_CHECK(callContractFunction("f(address)", encodeArgs(u160(libraryAddress))), encodeArgs(false)); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); + BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); + ABI_CHECK(callContractFunction("f(address)", encodeArgs(u160(m_contractAddress))), encodeArgs(true)); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10); + BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0); } -BOOST_AUTO_TEST_CASE(shift_left_assignment_different_type) +BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) { + // Check allocation size of byte array. Should be 32 plus length rounded up to next + // multiple of 32 char const* sourceCode = R"( contract C { - function f(uint a, uint8 b) public returns (uint) { - a <<= b; - return a; + function f() public pure returns (uint d1, uint d2, uint d3, uint memsize) { + bytes memory b1 = new bytes(31); + bytes memory b2 = new bytes(32); + bytes memory b3 = new bytes(256); + bytes memory b4 = new bytes(31); + assembly { + d1 := sub(b2, b1) + d2 := sub(b3, b2) + d3 := sub(b4, b3) + memsize := msize() + } } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(8)), encodeArgs(u256(0x426600))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(16)), encodeArgs(u256(0x42660000))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(17)), encodeArgs(u256(0x84cc0000))); - ABI_CHECK(callContractFunction("f(uint256,uint8)", u256(0x4266), u256(240)), fromHex("4266000000000000000000000000000000000000000000000000000000000000")); + if (!m_optimiserSettings.runYulOptimiser) + { + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256, 0x260)); + } } -BOOST_AUTO_TEST_CASE(shift_right) +BOOST_AUTO_TEST_CASE(string_allocation_bug) { char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - return a >> b; + contract Sample + { + struct s { uint16 x; uint16 y; string a; string b;} + s[2] public p; + constructor() public { + s memory m; + m.x = 0xbbbb; + m.y = 0xcccc; + m.a = "hello"; + m.b = "world"; + p[0] = m; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(1)<<255, u256(5)), encodeArgs(u256(1)<<250)); + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs(u256(0xbbbb), u256(0xcccc), u256(0x80), u256(0xc0), u256(5), string("hello"), u256(5), string("world"))); } -BOOST_AUTO_TEST_CASE(shift_right_garbled) +BOOST_AUTO_TEST_CASE(using_for_function_on_int) { char const* sourceCode = R"( + library D { function double(uint self) public returns (uint) { return 2*self; } } contract C { - function f(uint8 a, uint8 b) public returns (uint) { - assembly { - a := 0xffffffff - } - // Higher bits should be cleared before the shift - return a >> b; + using D for uint; + function f(uint a) public returns (uint) { + return a.double(); } } )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(0xf))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(0xf))); -} - -BOOST_AUTO_TEST_CASE(shift_right_garbled_signed) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, uint8 b) public returns (int) { - assembly { - a := 0xfffffff0 - } - // Higher bits should be signextended before the shift - return a >> b; - } - function g(int8 a, uint8 b) public returns (int) { - assembly { - a := 0xf0 - } - // Higher bits should be signextended before the shift - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(9)), encodeArgs(u256(2 * 9))); } -BOOST_AUTO_TEST_CASE(shift_right_uint32) +BOOST_AUTO_TEST_CASE(using_for_function_on_struct) { char const* sourceCode = R"( + library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a >> b; + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 3; + return x.mul(a); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint32,uint32)", u256(0x4266), u256(17)), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(3 * 7))); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(3 * 7))); } -BOOST_AUTO_TEST_CASE(shift_right_uint8) +BOOST_AUTO_TEST_CASE(using_for_overload) { char const* sourceCode = R"( + library D { + struct s { uint a; } + function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } + function mul(s storage self, bytes32 x) public returns (bytes32) { } + } contract C { - function f(uint8 a, uint8 b) public returns (uint) { - return a >> b; + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return x.mul(a); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(0)), encodeArgs(u256(0x66))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x66), u256(8)), encodeArgs(u256(0x0))); + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); } -BOOST_AUTO_TEST_CASE(shift_right_assignment) +BOOST_AUTO_TEST_CASE(using_for_by_name) { char const* sourceCode = R"( + library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } contract C { - function f(uint a, uint b) public returns (uint) { - a >>= b; - return a; + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return x.mul({x: a}); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(uint256,uint256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_right_assignment_signed) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a >>= b; - return a; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(0)), encodeArgs(u256(0x4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(8)), encodeArgs(u256(0x42))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(16)), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(0x4266), u256(17)), encodeArgs(u256(0))); + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); } -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue) +BOOST_AUTO_TEST_CASE(bound_function_in_function) { char const* sourceCode = R"( + library L { + function g(function() internal returns (uint) _t) internal returns (uint) { return _t(); } + } contract C { - function f(int a, int b) public returns (int) { - return a >> b; + using L for *; + function f() public returns (uint) { + return t.g(); } + function t() public pure returns (uint) { return 7; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_literal) -{ - char const* sourceCode = R"( - contract C { - function f1() public pure returns (bool) { - return (-4266 >> 0) == -4266; - } - function f2() public pure returns (bool) { - return (-4266 >> 1) == -2133; - } - function f3() public pure returns (bool) { - return (-4266 >> 4) == -267; - } - function f4() public pure returns (bool) { - return (-4266 >> 8) == -17; - } - function f5() public pure returns (bool) { - return (-4266 >> 16) == -1; - } - function f6() public pure returns (bool) { - return (-4266 >> 17) == -1; - } - function g1() public pure returns (bool) { - return (-4267 >> 0) == -4267; - } - function g2() public pure returns (bool) { - return (-4267 >> 1) == -2134; - } - function g3() public pure returns (bool) { - return (-4267 >> 4) == -267; - } - function g4() public pure returns (bool) { - return (-4267 >> 8) == -17; - } - function g5() public pure returns (bool) { - return (-4267 >> 16) == -1; - } - function g6() public pure returns (bool) { - return (-4267 >> 17) == -1; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f5()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("f6()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g1()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g2()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g3()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g4()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g5()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("g6()"), encodeArgs(true)); - ) -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int8) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, int8 b) public returns (int) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(0)), encodeArgs(u256(-66))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(1)), encodeArgs(u256(-33))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(4)), encodeArgs(u256(-5))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(8)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-66), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(0)), encodeArgs(u256(-67))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(1)), encodeArgs(u256(-34))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(4)), encodeArgs(u256(-5))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(8)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(-67), u256(17)), encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int8) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, int8 b) public returns (int8) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); + compileAndRun(sourceCode, 0, "L"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16) +BOOST_AUTO_TEST_CASE(bound_function_in_var) { char const* sourceCode = R"( - contract C { - function f(int16 a, int16 b) public returns (int16) { - return a >> b; - } + library D { struct s { uint a; } function mul(s storage self, uint x) public returns (uint) { return self.a *= x; } } + contract C { + using D for D.s; + D.s public x; + function f(uint a) public returns (uint) { + x.a = 6; + return (x.mul)({x: a}); } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); + } + )"; + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f(uint256)", u256(7)), encodeArgs(u256(6 * 7))); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(6 * 7))); } -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32) +BOOST_AUTO_TEST_CASE(bound_function_to_string) { char const* sourceCode = R"( - contract C { - function f(int32 a, int32 b) public returns (int32) { - return a >> b; - } + library D { function length(string memory self) public returns (uint) { return bytes(self).length; } } + contract C { + using D for string; + string x; + function f() public returns (uint) { + x = "abc"; + return x.length(); } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); + function g() public returns (uint) { + string memory s = "abc"; + return s.length(); + } + } + )"; + compileAndRun(sourceCode, 0, "D"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"D", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(3))); + ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(3))); } - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int16) +BOOST_AUTO_TEST_CASE(inline_long_string_return) { - char const* sourceCode = R"( - contract C { - function f(int16 a, int16 b) public returns (int) { - return a >> b; - } + char const* sourceCode = R"( + contract C { + function f() public returns (string memory) { + return (["somethingShort", "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"][1]); } - )"; + } + )"; + + string strLong = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(-4267), u256(17)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("f()"), encodeDyn(strLong)); } -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int32) +BOOST_AUTO_TEST_CASE(fixed_bytes_index_access) { char const* sourceCode = R"( - contract C { - function f(int32 a, int32 b) public returns (int) { - return a >> b; - } + contract C { + bytes16[] public data; + function f(bytes32 x) public returns (byte) { + return x[2]; } - )"; + function g(bytes32 x) public returns (uint) { + data = [x[0], x[1], x[2]]; + data[0] = "12345"; + return uint(uint8(data[0][4])); + } + } + )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(-4267), u256(17)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs("9")); + ABI_CHECK(callContractFunction("g(bytes32)", "789"), encodeArgs(u256(int('5')))); + ABI_CHECK(callContractFunction("data(uint256)", u256(1)), encodeArgs("8")); } -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_assignment) +BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) { + // Test for a bug where higher order bits cleanup was not done for array index access. char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a >>= b; - return a; + contract C { + function f(uint x) public returns (uint[256] memory r){ + r[uint8(x)] = 2; + } } - } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(0)), encodeArgs(u256(-4266))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(1)), encodeArgs(u256(-2133))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4266), u256(17)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(0)), encodeArgs(u256(-4267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(1)), encodeArgs(u256(-2134))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(4)), encodeArgs(u256(-267))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(8)), encodeArgs(u256(-17))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(16)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(-4267), u256(17)), encodeArgs(u256(-1))); + // neither of the two should throw due to out-of-bounds access + BOOST_CHECK(callContractFunction("f(uint256)", u256(0x01)).size() == 256 * 32); + BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32); } -BOOST_AUTO_TEST_CASE(shift_negative_rvalue) +BOOST_AUTO_TEST_CASE(cleanup_bytes_types) { + // Checks that bytesXX types are properly cleaned before they are compared. char const* sourceCode = R"( contract C { - function f(int a, int b) public returns (int) { - return a << b; - } - function g(int a, int b) public returns (int) { - return a >> b; + function f(bytes2 a, uint16 x) public returns (uint) { + if (a != "ab") return 1; + if (x != 0x0102) return 2; + if (bytes3(uint24(x)) != 0x000102) return 3; + return 0; } } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(1), u256(-1)), encodeArgs()); - ABI_CHECK(callContractFunction("g(int256,int256)", u256(1), u256(-1)), encodeArgs()); + // We input longer data on purpose. + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), v2 ? encodeArgs() : encodeArgs(0)); } - -BOOST_AUTO_TEST_CASE(shift_negative_rvalue_assignment) +BOOST_AUTO_TEST_CASE(cleanup_address_types) { + // Checks that address types are properly cleaned before they are compared. char const* sourceCode = R"( contract C { - function f(int a, int b) public returns (int) { - a <<= b; - return a; + function f(address a) public returns (uint) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; } - function g(int a, int b) public returns (int) { - a >>= b; - return a; + function g(address payable a) public returns (uint) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; } } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(int256,int256)", u256(1), u256(-1)), encodeArgs()); - ABI_CHECK(callContractFunction("g(int256,int256)", u256(1), u256(-1)), encodeArgs()); + + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + // We input longer data on purpose. + ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); + ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(shift_constant_left_assignment) +BOOST_AUTO_TEST_CASE(failed_create) { char const* sourceCode = R"( + contract D { constructor() public payable {} } contract C { - function f() public returns (uint a) { - a = 0x42; - a <<= 8; + uint public x; + constructor() public payable {} + function f(uint amount) public returns (D) { + x++; + return (new D).value(amount)(); + } + function stack(uint depth) public returns (address) { + if (depth < 1024) + return this.stack(depth - 1); + else + return address(f(0)); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x4200))); + compileAndRun(sourceCode, 20, "C"); + BOOST_CHECK(callContractFunction("f(uint256)", 20) != encodeArgs(u256(0))); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); + ABI_CHECK(callContractFunction("f(uint256)", 20), encodeArgs()); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); + ABI_CHECK(callContractFunction("stack(uint256)", 1023), encodeArgs()); + ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); } -BOOST_AUTO_TEST_CASE(shift_constant_right_assignment) +BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor) { + // Memory arrays are initialized using calldatacopy past the size of the calldata. + // This test checks that it also works in the constructor context. char const* sourceCode = R"( contract C { - function f() public returns (uint a) { - a = 0x4200; - a >>= 8; + bool public success; + constructor() public { + // Make memory dirty. + assembly { + for { let i := 0 } lt(i, 64) { i := add(i, 1) } { + mstore(msize(), not(0)) + } + } + uint16[3] memory c; + require(c[0] == 0 && c[1] == 0 && c[2] == 0); + uint16[] memory x = new uint16[](3); + require(x[0] == 0 && x[1] == 0 && x[2] == 0); + success = true; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x42))); + // Cannot run against yul optimizer because of msize + if (!m_optimiserSettings.runYulOptimiser) + { + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("success()"), encodeArgs(u256(1))); + } } -BOOST_AUTO_TEST_CASE(shift_cleanup) +BOOST_AUTO_TEST_CASE(mutex) { char const* sourceCode = R"( - contract C { - function f() public returns (uint16 x) { - x = 0xffff; - x += 32; - x <<= 8; - x >>= 16; + contract mutexed { + bool locked; + modifier protected { + if (locked) revert(); + locked = true; + _; + locked = false; + } + } + contract Fund is mutexed { + uint shares; + constructor() public payable { shares = msg.value; } + function withdraw(uint amount) public protected returns (uint) { + // NOTE: It is very bad practice to write this function this way. + // Please refer to the documentation of how to do this properly. + if (amount > shares) revert(); + (bool success,) = msg.sender.call.value(amount)(""); + require(success); + shares -= amount; + return shares; + } + function withdrawUnprotected(uint amount) public returns (uint) { + // NOTE: It is very bad practice to write this function this way. + // Please refer to the documentation of how to do this properly. + if (amount > shares) revert(); + (bool success,) = msg.sender.call.value(amount)(""); + require(success); + shares -= amount; + return shares; + } + } + contract Attacker { + Fund public fund; + uint callDepth; + bool protected; + function setProtected(bool _protected) public { protected = _protected; } + constructor(Fund _fund) public { fund = _fund; } + function attack() public returns (uint) { + callDepth = 0; + return attackInternal(); + } + function attackInternal() internal returns (uint) { + if (protected) + return fund.withdraw(10); + else + return fund.withdrawUnprotected(10); + } + fallback() external payable { + callDepth++; + if (callDepth < 4) + attackInternal(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); + compileAndRun(sourceCode, 500, "Fund"); + auto fund = m_contractAddress; + BOOST_CHECK_EQUAL(balanceAt(fund), 500); + compileAndRun(sourceCode, 0, "Attacker", encodeArgs(u160(fund))); + ABI_CHECK(callContractFunction("setProtected(bool)", true), encodeArgs()); + ABI_CHECK(callContractFunction("attack()"), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(fund), 500); + ABI_CHECK(callContractFunction("setProtected(bool)", false), encodeArgs()); + ABI_CHECK(callContractFunction("attack()"), encodeArgs(u256(460))); + BOOST_CHECK_EQUAL(balanceAt(fund), 460); } -BOOST_AUTO_TEST_CASE(shift_cleanup_garbled) +BOOST_AUTO_TEST_CASE(payable_function) { char const* sourceCode = R"( contract C { - function f() public returns (uint8 x) { - assembly { - x := 0xffff - } - x >>= 8; + uint public a; + function f() payable public returns (uint) { + return msg.value; + } + fallback() external payable { + a = msg.value + 1; } } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); + ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(27))); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27); + ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); + ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(28))); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); } -BOOST_AUTO_TEST_CASE(shift_overflow) +BOOST_AUTO_TEST_CASE(payable_function_calls_library) { char const* sourceCode = R"( + library L { + function f() public returns (uint) { return 7; } + } contract C { - function leftU(uint8 x, uint8 y) public returns (uint8) { - return x << y; - } - function leftS(int8 x, int8 y) public returns (int8) { - return x << y; + function f() public payable returns (uint) { + return L.f(); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 8), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 1), encodeArgs(u256(254))); - ABI_CHECK(callContractFunction("leftU(uint8,uint8)", 255, 0), encodeArgs(u256(255))); - - // Result is -128 and output is sign-extended, not zero-padded. - ABI_CHECK(callContractFunction("leftS(int8,int8)", 1, 7), encodeArgs(u256(0) - 128)); - ABI_CHECK(callContractFunction("leftS(int8,int8)", 1, 6), encodeArgs(u256(64))); + compileAndRun(sourceCode, 0, "L"); + compileAndRun(sourceCode, 0, "C", bytes(), map{{"L", m_contractAddress}}); + ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(shift_bytes) +BOOST_AUTO_TEST_CASE(non_payable_throw) { char const* sourceCode = R"( contract C { - function left(bytes20 x, uint8 y) public returns (bytes20) { - return x << y; + uint public a; + function f() public returns (uint) { + return msgvalue(); } - function right(bytes20 x, uint8 y) public returns (bytes20) { - return x >> y; + function msgvalue() internal returns (uint) { + return msg.value; + } + fallback() external { + update(); } + function update() internal { + a = msg.value + 1; + } + } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("left(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs("901234567890" + string(8, 0))); - ABI_CHECK(callContractFunction("right(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); + ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); + ABI_CHECK(callContractFunction(""), encodeArgs()); + ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); + ABI_CHECK(callContractFunctionWithValue("", 27), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); + ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1))); + ABI_CHECK(callContractFunctionWithValue("a()", 27), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); } -BOOST_AUTO_TEST_CASE(shift_bytes_cleanup) +BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier) { char const* sourceCode = R"( contract C { - function left(uint8 y) public returns (bytes20) { - bytes20 x; - assembly { x := "12345678901234567890abcde" } - return x << y; + modifier tryCircumvent { + if (false) _; // avoid the function, we should still not accept ether } - function right(uint8 y) public returns (bytes20) { - bytes20 x; - assembly { x := "12345678901234567890abcde" } - return x >> y; + function f() tryCircumvent public returns (uint) { + return msgvalue(); + } + function msgvalue() internal returns (uint) { + return msg.value; } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("left(uint8)", 8 * 8), encodeArgs("901234567890" + string(8, 0))); - ABI_CHECK(callContractFunction("right(uint8)", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); + ALSO_VIA_YUL( + compileAndRun(sourceCode); + ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs()); + BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); + ) } -BOOST_AUTO_TEST_CASE(exp_cleanup) +BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) { + // This tests that memory resize for return values is not paid during the call, which would + // make the gas calculation overly complex. We access the end of the output area before + // the call is made. + // Tests that this also survives the optimizer. char const* sourceCode = R"( contract C { - function f() public pure returns (uint8 x) { - uint8 y = uint8(2) ** uint8(8); - return 0 ** y; - } + function f() public returns (uint[200] memory) {} + } + contract D { + function f(C c) public returns (uint) { c.f(); return 7; } } )"; + compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); + u160 cAddr = m_contractAddress; + compileAndRun(sourceCode, 0, "D"); + ABI_CHECK(callContractFunction("f(address)", cAddr), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(exp_cleanup_direct) +BOOST_AUTO_TEST_CASE(receive_external_function_type) { char const* sourceCode = R"( contract C { - function f() public pure returns (uint8 x) { - return uint8(0) ** uint8(uint8(2) ** uint8(8)); + function g() public returns (uint) { return 7; } + function f(function() external returns (uint) g) public returns (uint) { + return g(); } } )"; + compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); + ABI_CHECK(callContractFunction( + "f(function)", + m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) + ), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(exp_cleanup_nonzero_base) +BOOST_AUTO_TEST_CASE(return_external_function_type) { char const* sourceCode = R"( contract C { - function f() public pure returns (uint8 x) { - return uint8(0x166) ** uint8(uint8(2) ** uint8(8)); + function g() public {} + function f() public returns (function() external) { + return this.g; } } )"; + compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); + ABI_CHECK( + callContractFunction("f()"), + m_contractAddress.asBytes() + FixedHash<4>(util::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) + ); } -BOOST_AUTO_TEST_CASE(cleanup_in_compound_assign) +// TODO: store bound internal library functions + +BOOST_AUTO_TEST_CASE(shift_right_garbled) { char const* sourceCode = R"( contract C { - function test() public returns (uint, uint) { - uint32 a = 0xffffffff; - uint16 x = uint16(a); - uint16 y = x; - x /= 0x100; - y = y / 0x100; - return (x, y); + function f(uint8 a, uint8 b) public returns (uint) { + assembly { + a := 0xffffffff + } + // Higher bits should be cleared before the shift + return a >> b; } } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0xff), u256(0xff))); + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(0xf))); + ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(0xf))); } -BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers) +BOOST_AUTO_TEST_CASE(shift_right_garbled_signed) { char const* sourceCode = R"( - contract C { - modifier m { - uint a = 1; - assembly { - a := 2 + contract C { + function f(int8 a, uint8 b) public returns (int) { + assembly { + a := 0xfffffff0 + } + // Higher bits should be signextended before the shift + return a >> b; + } + function g(int8 a, uint8 b) public returns (int) { + assembly { + a := 0xf0 + } + // Higher bits should be signextended before the shift + return a >> b; } - if (a != 2) - revert(); - _; - } - function f() m public returns (bool) { - return true; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ) + )"; + compileAndRun(sourceCode, 0, "C"); + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); + ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); + ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); + ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); + ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); + ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } -BOOST_AUTO_TEST_CASE(packed_storage_overflow) +BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int8) { char const* sourceCode = R"( - contract C { - uint16 x = 0x1234; - uint16 a = 0xffff; - uint16 b; - function f() public returns (uint, uint, uint, uint) { - a++; - uint c = b; - delete b; - a -= 2; - return (x, c, b, a); + contract C { + function f(int8 a, int8 b) public returns (int8) { + return a >> b; + } } - } - )"; + )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe))); + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); + ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); + ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); + ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); + ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } -BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) +BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16) { char const* sourceCode = R"( - contract C1 {} - /** - **/ - contract C2 {} - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C1"); - compileAndRun(sourceCode, 0, "C2"); - ) + contract C { + function f(int16 a, int16 b) public returns (int16) { + return a >> b; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); + ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); + ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); + ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); + ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } - -BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) +BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32) { char const* sourceCode = R"( - contract D { - bytes a = hex"1237651237125387136581271652831736512837126583171583712358126123765123712538713658127165283173651283712658317158371235812612376512371253871365812716528317365128371265831715837123581261237651237125387136581271652831736512837126583171583712358126"; - bytes b = hex"1237651237125327136581271252831736512837126583171383712358126123765125712538713658127165253173651283712658357158371235812612376512371a5387136581271652a317365128371265a317158371235812612a765123712538a13658127165a83173651283712a58317158371235a126"; - constructor(uint) public {} - } - contract Double { - function f() public { - new D(2); - } - function g() public { - new D(3); - } - } - contract Single { - function f() public { - new D(2); + contract C { + function f(int32 a, int32 b) public returns (int32) { + return a >> b; + } } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK_LE( - double(m_compiler.object("Double").bytecode.size()), - 1.2 * double(m_compiler.object("Single").bytecode.size()) - ); + )"; + compileAndRun(sourceCode, 0, "C"); + bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; + ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); + ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); + ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); + ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); + ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } -BOOST_AUTO_TEST_CASE(recursive_structs) +BOOST_AUTO_TEST_CASE(shift_bytes) { char const* sourceCode = R"( contract C { - struct S { - S[] x; + function left(bytes20 x, uint8 y) public returns (bytes20) { + return x << y; } - S sstorage; - function f() public returns (uint) { - S memory s; - s.x = new S[](10); - delete s; - // TODO Uncomment after implemented. - // sstorage.x.push(); - delete sstorage; - return 1; + function right(bytes20 x, uint8 y) public returns (bytes20) { + return x >> y; } } )"; compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); + ABI_CHECK(callContractFunction("left(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs("901234567890" + string(8, 0))); + ABI_CHECK(callContractFunction("right(bytes20,uint8)", "12345678901234567890", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); } -BOOST_AUTO_TEST_CASE(invalid_instruction) +BOOST_AUTO_TEST_CASE(shift_bytes_cleanup) { char const* sourceCode = R"( contract C { - function f() public { - assembly { - invalid() - } + function left(uint8 y) public returns (bytes20) { + bytes20 x; + assembly { x := "12345678901234567890abcde" } + return x << y; + } + function right(uint8 y) public returns (bytes20) { + bytes20 x; + assembly { x := "12345678901234567890abcde" } + return x >> y; } } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ) + )"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("left(uint8)", 8 * 8), encodeArgs("901234567890" + string(8, 0))); + ABI_CHECK(callContractFunction("right(uint8)", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); } -BOOST_AUTO_TEST_CASE(assert_require) +BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) { char const* sourceCode = R"( - contract C { - function f() public { - assert(false); - } - function g(bool val) public returns (bool) { - assert(val == true); - return true; - } - function h(bool val) public returns (bool) { - require(val); - return true; - } - } + contract C1 {} + /** + **/ + contract C2 {} )"; ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g(bool)", false), encodeArgs()); - ABI_CHECK(callContractFunction("g(bool)", true), encodeArgs(true)); - ABI_CHECK(callContractFunction("h(bool)", false), encodeArgs()); - ABI_CHECK(callContractFunction("h(bool)", true), encodeArgs(true)); + compileAndRun(sourceCode, 0, "C1"); + compileAndRun(sourceCode, 0, "C2"); ) } -BOOST_AUTO_TEST_CASE(revert) +BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) { char const* sourceCode = R"( - contract C { - uint public a = 42; + contract D { + bytes a = hex"1237651237125387136581271652831736512837126583171583712358126123765123712538713658127165283173651283712658317158371235812612376512371253871365812716528317365128371265831715837123581261237651237125387136581271652831736512837126583171583712358126"; + bytes b = hex"1237651237125327136581271252831736512837126583171383712358126123765125712538713658127165253173651283712658357158371235812612376512371a5387136581271652a317365128371265a317158371235812612a765123712538a13658127165a83173651283712a58317158371235a126"; + constructor(uint) public {} + } + contract Double { function f() public { - a = 1; - revert(); + new D(2); } function g() public { - a = 1; - assembly { - revert(0, 0) - } + new D(3); + } + } + contract Single { + function f() public { + new D(2); } } )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(42))); + compileAndRun(sourceCode); + BOOST_CHECK_LE( + double(m_compiler.object("Double").bytecode.size()), + 1.2 * double(m_compiler.object("Single").bytecode.size()) + ); } BOOST_AUTO_TEST_CASE(revert_with_cause) @@ -12249,85 +6618,6 @@ BOOST_AUTO_TEST_CASE(bubble_up_error_messages_through_create) } } -BOOST_AUTO_TEST_CASE(negative_stack_height) -{ - // This code was causing negative stack height during code generation - // because the stack height was not adjusted at the beginning of functions. - char const* sourceCode = R"( - contract C { - mapping(uint => Invoice) public invoices; - struct Invoice { - uint AID; - bool Aboola; - bool Aboolc; - bool exists; - } - function nredit(uint startindex) public pure returns(uint[500] memory CIDs, uint[500] memory dates, uint[500] memory RIDs, bool[500] memory Cboolas, uint[500] memory amounts){} - function return500InvoicesByDates(uint begindate, uint enddate, uint startindex) public view returns(uint[500] memory AIDs, bool[500] memory Aboolas, uint[500] memory dates, bytes32[3][500] memory Abytesas, bytes32[3][500] memory bytesbs, bytes32[2][500] memory bytescs, uint[500] memory amounts, bool[500] memory Aboolbs, bool[500] memory Aboolcs){} - function return500PaymentsByDates(uint begindate, uint enddate, uint startindex) public view returns(uint[500] memory BIDs, uint[500] memory dates, uint[500] memory RIDs, bool[500] memory Bboolas, bytes32[3][500] memory bytesbs,bytes32[2][500] memory bytescs, uint[500] memory amounts, bool[500] memory Bboolbs){} - } - )"; - compileAndRun(sourceCode, 0, "C"); -} - -BOOST_AUTO_TEST_CASE(literal_empty_string) -{ - char const* sourceCode = R"( - contract C { - bytes32 public x; - uint public a; - function f(bytes32 _x, uint _a) public { - x = _x; - a = _a; - } - function g() public { - this.f("", 2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(scientific_notation) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return 2e10 wei; - } - function g() public returns (uint) { - return 200e-2 wei; - } - function h() public returns (uint) { - return 2.5e1; - } - function i() public returns (int) { - return -2e10; - } - function j() public returns (int) { - return -200e-2; - } - function k() public returns (int) { - return -2.5e1; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(20000000000))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(2))); - ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(25))); - ABI_CHECK(callContractFunction("i()"), encodeArgs(u256(-20000000000))); - ABI_CHECK(callContractFunction("j()"), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("k()"), encodeArgs(u256(-25))); - ) -} - BOOST_AUTO_TEST_CASE(interface_contract) { char const* sourceCode = R"( @@ -12363,23 +6653,6 @@ BOOST_AUTO_TEST_CASE(interface_contract) ABI_CHECK(callContractFunction("f(address)", recipient), encodeArgs(true)); } -BOOST_AUTO_TEST_CASE(keccak256_assembly) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (bytes32 ret) { - assembly { - ret := keccak256(0, 0) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), fromHex("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); - ) -} - BOOST_AUTO_TEST_CASE(multi_modifiers) { // This triggered a bug in some version because the variable in the modifier was not @@ -12407,26 +6680,6 @@ BOOST_AUTO_TEST_CASE(multi_modifiers) ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(12))); } -BOOST_AUTO_TEST_CASE(inlineasm_empty_let) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint a, uint b) { - assembly { - let x - let y, z - a := x - b := z - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0), u256(0))); - ) -} - BOOST_AUTO_TEST_CASE(bare_call_invalid_address) { char const* sourceCode = R"YY( @@ -12691,140 +6944,6 @@ BOOST_AUTO_TEST_CASE(function_types_sig) ABI_CHECK(callContractFunction("i()"), encodeArgs(asString(FixedHash<4>(util::keccak256("x()")).asBytes()))); } -BOOST_AUTO_TEST_CASE(constant_string) -{ - char const* sourceCode = R"( - contract C { - bytes constant a = "\x03\x01\x02"; - bytes constant b = hex"030102"; - string constant c = "hello"; - function f() public returns (bytes memory) { - return a; - } - function g() public returns (bytes memory) { - return b; - } - function h() public returns (bytes memory) { - return bytes(c); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeDyn(string("\x03\x01\x02"))); - ABI_CHECK(callContractFunction("g()"), encodeDyn(string("\x03\x01\x02"))); - ABI_CHECK(callContractFunction("h()"), encodeDyn(string("hello"))); -} - -BOOST_AUTO_TEST_CASE(address_overload_resolution) -{ - char const* sourceCode = R"( - contract C { - function balance() public returns (uint) { - return 1; - } - function transfer(uint amount) public returns (uint) { - return amount; - } - } - contract D { - function f() public returns (uint) { - return (new C()).balance(); - } - function g() public returns (uint) { - return (new C()).transfer(5); - } - } - )"; - compileAndRun(sourceCode, 0, "D"); - BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5))); -} - -BOOST_AUTO_TEST_CASE(abi_encode) -{ - char const* sourceCode = R"( - contract C { - function f0() public returns (bytes memory) { - return abi.encode(); - } - function f1() public returns (bytes memory) { - return abi.encode(1, 2); - } - function f2() public returns (bytes memory) { - string memory x = "abc"; - return abi.encode(1, x, 2); - } - function f3() public returns (bytes memory r) { - // test that memory is properly allocated - string memory x = "abc"; - r = abi.encode(1, x, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - function f4() public returns (bytes memory) { - bytes4 x = "abcd"; - return abi.encode(bytes2(x)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f0()"), encodeArgs(0x20, 0)); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 0x40, 1, 2)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 0x20, "ab")); -} - -BOOST_AUTO_TEST_CASE(abi_encode_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f0() public pure returns (bytes memory) { - return abi.encode(); - } - function f1() public pure returns (bytes memory) { - return abi.encode(1, 2); - } - function f2() public pure returns (bytes memory) { - string memory x = "abc"; - return abi.encode(1, x, 2); - } - function f3() public pure returns (bytes memory r) { - // test that memory is properly allocated - string memory x = "abc"; - r = abi.encode(1, x, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - S s; - function f4() public returns (bytes memory r) { - string memory x = "abc"; - s.a = 7; - s.b.push(2); - s.b.push(3); - r = abi.encode(1, x, s, 2); - bytes memory y = "def"; - require(y[0] == "d"); - y[0] = "e"; - require(y[0] == "e"); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f0()"), encodeArgs(0x20, 0)); - ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 0x40, 1, 2)); - ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 0xa0, 1, 0x60, 2, 3, "abc")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 0x160, 1, 0x80, 0xc0, 2, 3, "abc", 7, 0x40, 2, 2, 3)); -} - - BOOST_AUTO_TEST_CASE(abi_encodePacked) { char const* sourceCode = R"( @@ -12867,11 +6986,7 @@ BOOST_AUTO_TEST_CASE(abi_encodePacked) ABI_CHECK(callContractFunction("f1()"), encodeArgs(0x20, 2, "\x01\x02")); ABI_CHECK(callContractFunction("f2()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); ABI_CHECK(callContractFunction("f3()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); - ABI_CHECK(callContractFunction("f4()"), encodeArgs( - 0x20, - 2 + 26 + 26 + 2, - "\x07\x01" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "\x12\x01" - )); + ABI_CHECK(callContractFunction("f4()"), encodeArgs(0x20, 2 + 26 + 26 + 2, "\x07\x01" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "\x12\x01")); ABI_CHECK(callContractFunction("f_literal()"), encodeArgs(0x20, 5, "\x01" "abc" "\x02")); ABI_CHECK(callContractFunction("f_calldata()"), encodeArgs(0x20, 6, "\x01" "\xa5\xbf\xa1\xee" "\x02")); } @@ -12958,10 +7073,7 @@ BOOST_AUTO_TEST_CASE(abi_encodePacked_from_storage) ABI_CHECK(callContractFunction("lf()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02")); ABI_CHECK(callContractFunction("ld()"), encodeArgs(0x20, 5 * 32 + 2, "\x01" + asString(encodeArgs(payload)) + "\x02")); ABI_CHECK(callContractFunction("bytes_short()"), encodeArgs(0x20, 6, "\x01" "abcd\x02")); - ABI_CHECK( - callContractFunction("bytes_long()"), - encodeArgs(0x20, 42, "\x01" "0123456789012345678901234567890123456789\x02") - ); + ABI_CHECK(callContractFunction("bytes_long()"), encodeArgs(0x20, 42, "\x01" "0123456789012345678901234567890123456789\x02")); } } @@ -13196,7 +7308,6 @@ BOOST_AUTO_TEST_CASE(event_signature_in_library) BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16),(uint8,int16))"))); } - BOOST_AUTO_TEST_CASE(abi_encode_with_selector) { char const* sourceCode = R"( @@ -13379,108 +7490,26 @@ BOOST_AUTO_TEST_CASE(abi_encode_with_signaturev2) BOOST_AUTO_TEST_CASE(abi_encode_empty_string) { - char const* sourceCode = R"( - // Tests that this will not end up using a "bytes0" type - // (which would assert) - contract C { - function f() public pure returns (bytes memory, bytes memory) { - return (abi.encode(""), abi.encodePacked("")); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - if (!solidity::test::CommonOptions::get().useABIEncoderV2) - { - // ABI Encoder V2 has slightly different padding, tested below. - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x40, 0xc0, - 0x60, 0x20, 0x00, 0x00, - 0x00 - )); - } -} - -BOOST_AUTO_TEST_CASE(abi_encode_empty_string_v2) -{ - char const* sourceCode = R"( - // Tests that this will not end up using a "bytes0" type - // (which would assert) - pragma experimental ABIEncoderV2; - contract C { - function f() public pure returns (bytes memory, bytes memory) { - return (abi.encode(""), abi.encodePacked("")); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x40, 0xa0, - 0x40, 0x20, 0x00, - 0x00 - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_rational) -{ - char const* sourceCode = R"( - // Tests that rational numbers (even negative ones) are encoded properly. - contract C { - function f() public pure returns (bytes memory) { - return abi.encode(1, -2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x20, - 0x40, u256(1), u256(-2) - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_rational_v2) -{ - char const* sourceCode = R"( - // Tests that rational numbers (even negative ones) are encoded properly. - pragma experimental ABIEncoderV2; - contract C { - function f() public pure returns (bytes memory) { - return abi.encode(1, -2); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x20, - 0x40, u256(1), u256(-2) - )); -} - -BOOST_AUTO_TEST_CASE(abi_encode_call) -{ - char const* sourceCode = R"T( + char const* sourceCode = R"( + // Tests that this will not end up using a "bytes0" type + // (which would assert) contract C { - bool x; - function c(uint a, uint[] memory b) public { - require(a == 5); - require(b.length == 2); - require(b[0] == 6); - require(b[1] == 7); - x = true; - } - function f() public returns (bool) { - uint a = 5; - uint[] memory b = new uint[](2); - b[0] = 6; - b[1] = 7; - (bool success,) = address(this).call(abi.encodeWithSignature("c(uint256,uint256[])", a, b)); - require(success); - return x; + function f() public pure returns (bytes memory, bytes memory) { + return (abi.encode(""), abi.encodePacked("")); } } - )T"; + )"; + compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); + if (!solidity::test::CommonOptions::get().useABIEncoderV2) + { + // ABI Encoder V2 has slightly different padding, tested below. + ABI_CHECK(callContractFunction("f()"), encodeArgs( + 0x40, 0xc0, + 0x60, 0x20, 0x00, 0x00, + 0x00 + )); + } } BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) @@ -13756,56 +7785,6 @@ BOOST_AUTO_TEST_CASE(bitwise_shifting_constantinople_combined) ) } -BOOST_AUTO_TEST_CASE(senders_balance) -{ - char const* sourceCode = R"( - contract C { - function f() public view returns (uint) { - return msg.sender.balance; - } - } - contract D { - C c = new C(); - constructor() public payable { } - function f() public view returns (uint) { - return c.f(); - } - } - )"; - compileAndRun(sourceCode, 27, "D"); - BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(27))); -} - -BOOST_AUTO_TEST_CASE(abi_decode_trivial) -{ - char const* sourceCode = R"( - contract C { - function f(bytes memory data) public pure returns (uint) { - return abi.decode(data, (uint)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20, 33), encodeArgs(u256(33))); -} - -BOOST_AUTO_TEST_CASE(abi_encode_decode_simple) -{ - char const* sourceCode = R"XX( - contract C { - function f() public pure returns (uint, bytes memory) { - bytes memory arg = "abcdefg"; - return abi.decode(abi.encode(uint(33), arg), (uint, bytes)); - } - } - )XX"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - BOOST_AUTO_TEST_CASE(abi_decode_simple) { char const* sourceCode = R"( @@ -13816,34 +7795,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_simple) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f() public pure returns (S memory) { - S memory s; - s.a = 8; - s.b = new uint[](3); - s.b[0] = 9; - s.b[1] = 10; - s.b[2] = 11; - return abi.decode(abi.encode(s), (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(0x20, 8, 0x40, 3, 9, 10, 11) - ); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(abi_decode_simple_storage) @@ -13858,36 +7810,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_simple_storage) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2_storage) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - bytes data; - struct S { uint a; uint[] b; } - function f() public returns (S memory) { - S memory s; - s.a = 8; - s.b = new uint[](3); - s.b[0] = 9; - s.b[1] = 10; - s.b[2] = 11; - data = abi.encode(s); - return abi.decode(data, (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f()"), - encodeArgs(0x20, 8, 0x40, 3, 9, 10, 11) - ); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(abi_decode_calldata) @@ -13900,181 +7823,7 @@ BOOST_AUTO_TEST_CASE(abi_decode_calldata) } )"; compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), - encodeArgs(33, 0x40, 7, "abcdefg") - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_v2_calldata) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint a; uint[] b; } - function f(bytes calldata data) external pure returns (S memory) { - return abi.decode(data, (S)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 0x20 * 7, 0x20, 33, 0x40, 3, 10, 11, 12), - encodeArgs(0x20, 33, 0x40, 3, 10, 11, 12) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_static_array) -{ - char const* sourceCode = R"( - contract C { - function f(bytes calldata data) external pure returns (uint[2][3] memory) { - return abi.decode(data, (uint[2][3])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 1, 2, 3, 4, 5, 6), - encodeArgs(1, 2, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_static_array_v2) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes calldata data) external pure returns (uint[2][3] memory) { - return abi.decode(data, (uint[2][3])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 1, 2, 3, 4, 5, 6), - encodeArgs(1, 2, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(abi_decode_dynamic_array) -{ - char const* sourceCode = R"( - contract C { - function f(bytes calldata data) external pure returns (uint[] memory) { - return abi.decode(data, (uint[])); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK( - callContractFunction("f(bytes)", 0x20, 6 * 0x20, 0x20, 4, 3, 4, 5, 6), - encodeArgs(0x20, 4, 3, 4, 5, 6) - ); -} - -BOOST_AUTO_TEST_CASE(write_storage_external) -{ - char const* sourceCode = R"( - contract C { - uint public x; - function f(uint y) public payable { - x = y; - } - function g(uint y) external { - x = y; - } - function h() public { - this.g(12); - } - } - contract D { - C c = new C(); - function f() public payable returns (uint) { - c.g(3); - return c.x(); - } - function g() public returns (uint) { - c.g(8); - return c.x(); - } - function h() public returns (uint) { - c.h(); - return c.x(); - } - } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(8)); - ABI_CHECK(callContractFunction("h()"), encodeArgs(12)); -} - -BOOST_AUTO_TEST_CASE(test_underscore_in_hex) -{ - char const* sourceCode = R"( - contract test { - function f(bool cond) public pure returns (uint) { - uint32 x = 0x1234_ab; - uint y = 0x1234_abcd_1234; - return cond ? x : y; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(u256(0x1234ab))); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(u256(0x1234abcd1234))); -} - -BOOST_AUTO_TEST_CASE(flipping_sign_tests) -{ - char const* sourceCode = R"( - contract test { - function f() public returns (bool){ - int x = -2**255; - assert(-x == x); - return true; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} -BOOST_AUTO_TEST_CASE(external_public_override) -{ - char const* sourceCode = R"( - contract A { - function f() external virtual returns (uint) { return 1; } - } - contract B is A { - function f() public override returns (uint) { return 2; } - function g() public returns (uint) { return f(); } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(base_access_to_function_type_variables) -{ - char const* sourceCode = R"( - contract C { - function () internal returns (uint) x; - function set() public { - C.x = g; - } - function g() public pure returns (uint) { return 2; } - function h() public returns (uint) { return C.x(); } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("h()"), encodeArgs()); - ABI_CHECK(callContractFunction("set()"), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); + ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); } BOOST_AUTO_TEST_CASE(code_access) @@ -14118,91 +7867,6 @@ BOOST_AUTO_TEST_CASE(code_access) ABI_CHECK(codeRuntime1, codeRuntime2); } -BOOST_AUTO_TEST_CASE(code_access_padding) -{ - char const* sourceCode = R"( - contract C { - function diff() public pure returns (uint remainder) { - bytes memory a = type(D).creationCode; - bytes memory b = type(D).runtimeCode; - assembly { remainder := mod(sub(b, a), 0x20) } - } - } - contract D { - function f() public pure returns (uint) { return 7; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // This checks that the allocation function pads to multiples of 32 bytes - ABI_CHECK(callContractFunction("diff()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(code_access_create) -{ - char const* sourceCode = R"( - contract C { - function test() public returns (uint) { - bytes memory c = type(D).creationCode; - D d; - assembly { - d := create(0, add(c, 0x20), mload(c)) - } - return d.f(); - } - } - contract D { - uint x; - constructor() public { x = 7; } - function f() public view returns (uint) { return x; } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(7)); -} - -BOOST_AUTO_TEST_CASE(code_access_content) -{ - char const* sourceCode = R"( - contract C { - function testRuntime() public returns (bool) { - D d = new D(); - bytes32 runtimeHash = keccak256(type(D).runtimeCode); - bytes32 otherHash; - uint size; - assembly { - size := extcodesize(d) - extcodecopy(d, mload(0x40), 0, size) - otherHash := keccak256(mload(0x40), size) - } - require(size == type(D).runtimeCode.length); - require(runtimeHash == otherHash); - return true; - } - function testCreation() public returns (bool) { - D d = new D(); - bytes32 creationHash = keccak256(type(D).creationCode); - require(creationHash == d.x()); - return true; - } - } - contract D { - bytes32 public x; - constructor() public { - bytes32 codeHash; - assembly { - let size := codesize() - codecopy(mload(0x40), 0, size) - codeHash := keccak256(mload(0x40), size) - } - x = codeHash; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("testRuntime()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("testCreation()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(contract_name) { char const* sourceCode = R"( @@ -14295,22 +7959,6 @@ BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function) BOOST_CHECK(result != encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function_call) -{ - char const* sourceCode = R"( - contract Test { - function() internal x; - function f() public returns (uint r) { - x(); - return 2; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - ABI_CHECK(callContractFunction("f()"), bytes{}); -} - BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser) { char const* sourceCode = R"( diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol b/test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol new file mode 100644 index 000000000000..180d89ec185b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol @@ -0,0 +1,8 @@ +contract C { + function f(bytes calldata data) external pure returns (uint256[] memory) { + return abi.decode(data, (uint256[])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 -> 0x20, 0x4, 0x3, 0x4, 0x5, 0x6 diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol b/test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol new file mode 100644 index 000000000000..270a5abc0695 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol @@ -0,0 +1,12 @@ +contract C { + function f(bytes calldata data) + external + pure + returns (uint256[2][3] memory) + { + return abi.decode(data, (uint256[2][3])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol b/test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol new file mode 100644 index 000000000000..46450f704bda --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(bytes calldata data) + external + pure + returns (uint256[2][3] memory) + { + return abi.decode(data, (uint256[2][3])); + } +} + +// ---- +// f(bytes): 0x20, 0xc0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 -> 1, 2, 3, 4, 5, 6 diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol b/test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol new file mode 100644 index 000000000000..7b873951f676 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol @@ -0,0 +1,8 @@ +contract C { + function f(bytes memory data) public pure returns (uint256) { + return abi.decode(data, (uint256)); + } +} + +// ---- +// f(bytes): 0x20, 0x20, 0x21 -> 33 diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2.sol b/test/libsolidity/semanticTests/extracted/abi_decode_v2.sol new file mode 100644 index 000000000000..1dbf320bd534 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_v2.sol @@ -0,0 +1,22 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f() public pure returns (S memory) { + S memory s; + s.a = 8; + s.b = new uint256[](3); + s.b[0] = 9; + s.b[1] = 10; + s.b[2] = 11; + return abi.decode(abi.encode(s), (S)); + } +} + +// ---- +// f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol b/test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol new file mode 100644 index 000000000000..a5e7a9af8913 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f(bytes calldata data) external pure returns (S memory) { + return abi.decode(data, (S)); + } +} + +// ---- +// f(bytes): 0x20, 0xe0, 0x20, 0x21, 0x40, 0x3, 0xa, 0xb, 0xc -> 0x20, 0x21, 0x40, 0x3, 0xa, 0xb, 0xc diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol new file mode 100644 index 000000000000..95b667e474cc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + bytes data; + struct S { + uint256 a; + uint256[] b; + } + + function f() public returns (S memory) { + S memory s; + s.a = 8; + s.b = new uint256[](3); + s.b[0] = 9; + s.b[1] = 10; + s.b[2] = 11; + data = abi.encode(s); + return abi.decode(data, (S)); + } +} + +// ---- +// f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/extracted/abi_encode.sol b/test/libsolidity/semanticTests/extracted/abi_encode.sol new file mode 100644 index 000000000000..ac17cf80e532 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode.sol @@ -0,0 +1,36 @@ +contract C { + function f0() public returns (bytes memory) { + return abi.encode(); + } + + function f1() public returns (bytes memory) { + return abi.encode(1, 2); + } + + function f2() public returns (bytes memory) { + string memory x = "abc"; + return abi.encode(1, x, 2); + } + + function f3() public returns (bytes memory r) { + // test that memory is properly allocated + string memory x = "abc"; + r = abi.encode(1, x, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } + + function f4() public returns (bytes memory) { + bytes4 x = "abcd"; + return abi.encode(bytes2(x)); + } +} + +// ---- +// f0() -> 0x20, 0x0 +// f1() -> 0x20, 0x40, 0x1, 0x2 +// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f4() -> 0x20, 0x20, "ab" diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_call.sol b/test/libsolidity/semanticTests/extracted/abi_encode_call.sol new file mode 100644 index 000000000000..d73db5da6228 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_call.sol @@ -0,0 +1,26 @@ +contract C { + bool x; + + function c(uint256 a, uint256[] memory b) public { + require(a == 5); + require(b.length == 2); + require(b[0] == 6); + require(b[1] == 7); + x = true; + } + + function f() public returns (bool) { + uint256 a = 5; + uint256[] memory b = new uint256[](2); + b[0] = 6; + b[1] = 7; + (bool success, ) = address(this).call( + abi.encodeWithSignature("c(uint256,uint256[])", a, b) + ); + require(success); + return x; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol b/test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol new file mode 100644 index 000000000000..1fbcfa53d80f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure returns (uint256, bytes memory) { + bytes memory arg = "abcdefg"; + return abi.decode(abi.encode(uint256(33), arg), (uint256, bytes)); + } +} + +// ---- +// f() -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol b/test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol new file mode 100644 index 000000000000..373334ee7f2a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol @@ -0,0 +1,13 @@ +// Tests that this will not end up using a "bytes0" type +// (which would assert) +pragma experimental ABIEncoderV2; + + +contract C { + function f() public pure returns (bytes memory, bytes memory) { + return (abi.encode(""), abi.encodePacked("")); + } +} + +// ---- +// f() -> 0x40, 0xa0, 0x40, 0x20, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_rational.sol b/test/libsolidity/semanticTests/extracted/abi_encode_rational.sol new file mode 100644 index 000000000000..704fd54dcf89 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_rational.sol @@ -0,0 +1,9 @@ +// Tests that rational numbers (even negative ones) are encoded properly. +contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } +} + +// ---- +// f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol b/test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol new file mode 100644 index 000000000000..55047880a9b0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol @@ -0,0 +1,12 @@ +// Tests that rational numbers (even negative ones) are encoded properly. +pragma experimental ABIEncoderV2; + + +contract C { + function f() public pure returns (bytes memory) { + return abi.encode(1, -2); + } +} + +// ---- +// f() -> 0x20, 0x40, 0x1, -2 diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_v2.sol b/test/libsolidity/semanticTests/extracted/abi_encode_v2.sol new file mode 100644 index 000000000000..f6510b53da59 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_v2.sol @@ -0,0 +1,53 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[] b; + } + + function f0() public pure returns (bytes memory) { + return abi.encode(); + } + + function f1() public pure returns (bytes memory) { + return abi.encode(1, 2); + } + + function f2() public pure returns (bytes memory) { + string memory x = "abc"; + return abi.encode(1, x, 2); + } + + function f3() public pure returns (bytes memory r) { + // test that memory is properly allocated + string memory x = "abc"; + r = abi.encode(1, x, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } + + S s; + + function f4() public returns (bytes memory r) { + string memory x = "abc"; + s.a = 7; + s.b.push(2); + s.b.push(3); + r = abi.encode(1, x, s, 2); + bytes memory y = "def"; + require(y[0] == "d"); + y[0] = "e"; + require(y[0] == "e"); + } +} + +// ---- +// f0() -> 0x20, 0x0 +// f1() -> 0x20, 0x40, 0x1, 0x2 +// f2() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f3() -> 0x20, 0xa0, 0x1, 0x60, 0x2, 0x3, "abc" +// f4() -> 0x20, 0x160, 0x1, 0x80, 0xc0, 0x2, 0x3, "abc", 0x7, 0x40, 0x2, 0x2, 0x3 diff --git a/test/libsolidity/semanticTests/extracted/access_base_storage.sol b/test/libsolidity/semanticTests/extracted/access_base_storage.sol new file mode 100644 index 000000000000..a083ccd985b5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/access_base_storage.sol @@ -0,0 +1,30 @@ +contract Base { + uint256 dataBase; + + function getViaBase() public returns (uint256 i) { + return dataBase; + } +} + + +contract Derived is Base { + uint256 dataDerived; + + function setData(uint256 base, uint256 derived) public returns (bool r) { + dataBase = base; + dataDerived = derived; + return true; + } + + function getViaDerived() public returns (uint256 base, uint256 derived) { + base = dataBase; + derived = dataDerived; + } +} + +// ==== +// compileViaYul: also +// ---- +// setData(uint256,uint256): 1, 2 -> true +// getViaBase() -> 1 +// getViaDerived() -> 1, 2 diff --git a/test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol new file mode 100644 index 000000000000..a9402aa8641e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol @@ -0,0 +1,6 @@ +contract Lotto { + uint256 public constant ticketPrice = 555; +} + +// ---- +// ticketPrice() -> 555 diff --git a/test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol b/test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol new file mode 100644 index 000000000000..e2b59b5303de --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol @@ -0,0 +1,8 @@ +contract Lotto { + uint256 public ticketPrice = 500; +} + +// ==== +// compileViaYul: also +// ---- +// ticketPrice() -> 500 diff --git a/test/libsolidity/semanticTests/extracted/addmod_mulmod.sol b/test/libsolidity/semanticTests/extracted/addmod_mulmod.sol new file mode 100644 index 000000000000..d1e9f5c20211 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/addmod_mulmod.sol @@ -0,0 +1,12 @@ +contract C { + function test() public returns (uint256) { + // Note that this only works because computation on literals is done using + // unbounded integers. + if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) return 1; + if ((2**255 + 2**255) % 7 != addmod(2**255, 2**255, 7)) return 2; + return 0; + } +} + +// ---- +// test() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol b/test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol new file mode 100644 index 000000000000..7585980e1142 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol @@ -0,0 +1,24 @@ +contract C { + function f(uint256 d) public pure returns (uint256) { + addmod(1, 2, d); + return 2; + } + + function g(uint256 d) public pure returns (uint256) { + mulmod(1, 2, d); + return 2; + } + + function h() public pure returns (uint256) { + mulmod(0, 1, 2); + mulmod(1, 0, 2); + addmod(0, 1, 2); + addmod(1, 0, 2); + return 2; + } +} + +// ---- +// f(uint256): 0 -> FAILURE +// g(uint256): 0 -> FAILURE +// h() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/address_overload_resolution.sol b/test/libsolidity/semanticTests/extracted/address_overload_resolution.sol new file mode 100644 index 000000000000..9b68cc154c4d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/address_overload_resolution.sol @@ -0,0 +1,24 @@ +contract C { + function balance() public returns (uint256) { + return 1; + } + + function transfer(uint256 amount) public returns (uint256) { + return amount; + } +} + + +contract D { + function f() public returns (uint256) { + return (new C()).balance(); + } + + function g() public returns (uint256) { + return (new C()).transfer(5); + } +} + +// ---- +// f() -> 1 +// g() -> 5 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol b/test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol new file mode 100644 index 000000000000..f0afcffc99e0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol @@ -0,0 +1,21 @@ +contract c { + bytes8[] data1; // 4 per slot + bytes10[] data2; // 3 per slot + + function test() + public + returns (bytes10 a, bytes10 b, bytes10 c, bytes10 d, bytes10 e) + { + data1 = new bytes8[](9); + for (uint256 i = 0; i < data1.length; ++i) data1[i] = bytes8(uint64(i)); + data2 = data1; + a = data2[1]; + b = data2[2]; + c = data2[3]; + d = data2[4]; + e = data2[5]; + } +} + +// ---- +// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x05000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol b/test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol new file mode 100644 index 000000000000..9330d31623b3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol @@ -0,0 +1,15 @@ +contract c { + uint256[4][] a; + uint256[10][] b; + uint256[][] c; + + function test(uint256[2][] calldata d) external returns (uint256) { + a = d; + b = a; + c = b; + return c[1][1] | c[1][2] | c[1][3] | c[1][4]; + } +} + +// ---- +// test(uint256[2][]): 32, 3, 7, 8, 9, 10, 11, 12 -> 10 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol b/test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol new file mode 100644 index 000000000000..0e225f1e598c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol @@ -0,0 +1,20 @@ +// NOTE: This does not really test copying from storage to ABI directly, +// because it will always copy to memory first. +contract c { + int16[] x; + + function test() public returns (int16[] memory) { + x.push(int16(-1)); + x.push(int16(-1)); + x.push(int16(8)); + x.push(int16(-16)); + x.push(int16(-2)); + x.push(int16(6)); + x.push(int16(8)); + x.push(int16(-1)); + return x; + } +} + +// ---- +// test() -> 0x20, 0x8, -1, -1, 8, -16, -2, 6, 8, -1 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol b/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol new file mode 100644 index 000000000000..4432776fbc77 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol @@ -0,0 +1,14 @@ +contract c { + uint256[9] data1; + uint256[] data2; + + function test() public returns (uint256 x, uint256 y) { + data1[8] = 4; + data2 = data1; + x = data2.length; + y = data2[8]; + } +} + +// ---- +// test() -> 9, 4 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol new file mode 100644 index 000000000000..71601d477140 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol @@ -0,0 +1,17 @@ +contract c { + uint256[40] data1; + uint256[20] data2; + + function test() public returns (uint256 x, uint256 y) { + data1[30] = 4; + data1[2] = 7; + data1[3] = 9; + data2[3] = 8; + data1 = data2; + x = data1[3]; + y = data1[30]; // should be cleared + } +} + +// ---- +// test() -> 8, 0 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol b/test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol new file mode 100644 index 000000000000..1bbd95f6fae5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol @@ -0,0 +1,22 @@ +// since the copy always copies whole slots, we have to make sure that the source size maxes +// out a whole slot and at the same time there are still elements left in the target at that point +contract c { + bytes8[4] data1; // fits into one slot + bytes10[6] data2; // 4 elements need two slots + + function test() public returns (bytes10 r1, bytes10 r2, bytes10 r3) { + data1[0] = bytes8(uint64(1)); + data1[1] = bytes8(uint64(2)); + data1[2] = bytes8(uint64(3)); + data1[3] = bytes8(uint64(4)); + for (uint256 i = 0; i < data2.length; ++i) + data2[i] = bytes10(uint80(0xffff00 | (1 + i))); + data2 = data1; + r1 = data2[3]; + r2 = data2[4]; + r3 = data2[5]; + } +} + +// ---- +// test() -> 0x04000000000000000000000000000000000000000000000000, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol b/test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol new file mode 100644 index 000000000000..ab82589c22b6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol @@ -0,0 +1,21 @@ +contract c { + bytes8[9] data1; // 4 per slot + bytes17[10] data2; // 1 per slot, no offset counter + + function test() + public + returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) + { + for (uint256 i = 0; i < data1.length; ++i) data1[i] = bytes8(uint64(i)); + data2[8] = data2[9] = bytes8(uint64(2)); + data2 = data1; + a = data2[1]; + b = data2[2]; + c = data2[3]; + d = data2[4]; + e = data2[9]; + } +} + +// ---- +// test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x0 diff --git a/test/libsolidity/semanticTests/extracted/array_pop.sol b/test/libsolidity/semanticTests/extracted/array_pop.sol new file mode 100644 index 000000000000..5667b61d411c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_pop.sol @@ -0,0 +1,16 @@ +contract c { + uint256[] data; + + function test() public returns (uint256 x, uint256 l) { + data.push(7); + data.push(3); + x = data.length; + data.pop(); + x = data.length; + data.pop(); + l = data.length; + } +} + +// ---- +// test() -> 1, 0 diff --git a/test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol b/test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol new file mode 100644 index 000000000000..8fc018d72c5f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol @@ -0,0 +1,11 @@ +contract c { + uint256[] data; + + function test() public returns (bool) { + data.pop(); + return true; + } +} + +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/array_pop_isolated.sol b/test/libsolidity/semanticTests/extracted/array_pop_isolated.sol new file mode 100644 index 000000000000..2e6eac83e524 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_pop_isolated.sol @@ -0,0 +1,13 @@ +// This tests that the compiler knows the correct size of the function on the stack. +contract c { + uint256[] data; + + function test() public returns (uint256 x) { + x = 2; + data.pop; + x = 3; + } +} + +// ---- +// test() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/array_push.sol b/test/libsolidity/semanticTests/extracted/array_push.sol new file mode 100644 index 000000000000..bd8200a37dec --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_push.sol @@ -0,0 +1,19 @@ +contract c { + uint256[] data; + + function test() + public + returns (uint256 x, uint256 y, uint256 z, uint256 l) + { + data.push(5); + x = data[0]; + data.push(4); + y = data[1]; + data.push(3); + l = data.length; + z = data[2]; + } +} + +// ---- +// test() -> 5, 4, 3, 3 diff --git a/test/libsolidity/semanticTests/extracted/array_push_packed_array.sol b/test/libsolidity/semanticTests/extracted/array_push_packed_array.sol new file mode 100644 index 000000000000..dd5e2e85539a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_push_packed_array.sol @@ -0,0 +1,16 @@ +contract c { + uint80[] x; + + function test() public returns (uint80, uint80, uint80, uint80) { + x.push(1); + x.push(2); + x.push(3); + x.push(4); + x.push(5); + x.pop(); + return (x[0], x[1], x[2], x[3]); + } +} + +// ---- +// test() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/array_push_struct.sol b/test/libsolidity/semanticTests/extracted/array_push_struct.sol new file mode 100644 index 000000000000..e407fc0258cc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/array_push_struct.sol @@ -0,0 +1,23 @@ +contract c { + struct S { + uint16 a; + uint16 b; + uint16[3] c; + uint16[] d; + } + S[] data; + + function test() public returns (uint16, uint16, uint16, uint16) { + S memory s; + s.a = 2; + s.b = 3; + s.c[2] = 4; + s.d = new uint16[](4); + s.d[2] = 5; + data.push(s); + return (data[0].a, data[0].b, data[0].c[2], data[0].d[2]); + } +} + +// ---- +// test() -> 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/extracted/assert_require.sol b/test/libsolidity/semanticTests/extracted/assert_require.sol new file mode 100644 index 000000000000..6bd146a7a3aa --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/assert_require.sol @@ -0,0 +1,24 @@ +contract C { + function f() public { + assert(false); + } + + function g(bool val) public returns (bool) { + assert(val == true); + return true; + } + + function h(bool val) public returns (bool) { + require(val); + return true; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE +// g(bool): false -> FAILURE +// g(bool): true -> true +// h(bool): false -> FAILURE +// h(bool): true -> true diff --git a/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol new file mode 100644 index 000000000000..b83b1c598f84 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol @@ -0,0 +1,10 @@ +contract C { + uint256 constant x = 0x123 + 0x456; + + function f() public returns (uint256) { + return x + 1; + } +} + +// ---- +// f() -> 0x57a diff --git a/test/libsolidity/semanticTests/extracted/balance.sol b/test/libsolidity/semanticTests/extracted/balance.sol new file mode 100644 index 000000000000..d6a80dbf9bff --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/balance.sol @@ -0,0 +1,13 @@ +contract test { + constructor() public payable {} + + function getBalance() public returns (uint256 balance) { + return address(this).balance; + } +} + +// ==== +// compileViaYul: also +// ---- +// constructor(), 23 wei -> +// getBalance() -> 23 diff --git a/test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol b/test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol new file mode 100644 index 000000000000..753e9bd1e520 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol @@ -0,0 +1,21 @@ +contract C { + function() returns (uint256) internal x; + + function set() public { + C.x = g; + } + + function g() public pure returns (uint256) { + return 2; + } + + function h() public returns (uint256) { + return C.x(); + } +} + +// ---- +// g() -> 2 +// h() -> FAILURE +// set() -> +// h() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol b/test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol new file mode 100644 index 000000000000..2384c061f108 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol @@ -0,0 +1,24 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } +} + + +contract Base is BaseBase(7) { + constructor() public { + m_a *= m_a; + } +} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } +} + +// ---- +// getA() -> 49 diff --git a/test/libsolidity/semanticTests/extracted/break_in_modifier.sol b/test/libsolidity/semanticTests/extracted/break_in_modifier.sol new file mode 100644 index 000000000000..1d1036c2c8d2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/break_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + _; + break; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop.sol b/test/libsolidity/semanticTests/extracted/byte_array_pop.sol new file mode 100644 index 000000000000..5ed849702290 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_pop.sol @@ -0,0 +1,17 @@ +contract c { + bytes data; + + function test() public returns (uint256 x, uint256 y, uint256 l) { + data.push(0x07); + data.push(0x03); + x = data.length; + data.pop(); + data.pop(); + data.push(0x02); + y = data.length; + l = data.length; + } +} + +// ---- +// test() -> 2, 1, 1 diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol b/test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol new file mode 100644 index 000000000000..2589f1f558c0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol @@ -0,0 +1,12 @@ +contract c { + bytes data; + + function test() public returns (bytes memory) { + for (uint256 i = 0; i < 33; i++) data.push(0x03); + for (uint256 j = 0; j < 4; j++) data.pop(); + return data; + } +} + +// ---- +// test() -> 0x20, 29, 0x0303030303030303030303030303030303030303030303030303030303000000 diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol b/test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol new file mode 100644 index 000000000000..30ffa3a4c67c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol @@ -0,0 +1,14 @@ +contract c { + uint256 a; + uint256 b; + uint256 c; + bytes data; + + function test() public returns (bool) { + data.pop(); + return true; + } +} + +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol b/test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol new file mode 100644 index 000000000000..a9e3fd383bac --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol @@ -0,0 +1,13 @@ +// This tests that the compiler knows the correct size of the function on the stack. +contract c { + bytes data; + + function test() public returns (uint256 x) { + x = 2; + data.pop; + x = 3; + } +} + +// ---- +// test() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol b/test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol new file mode 100644 index 000000000000..1f6d500bd2a0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol @@ -0,0 +1,12 @@ +contract c { + bytes data; + + function test() public returns (bytes memory) { + for (uint256 i = 0; i < 34; i++) data.push(0x03); + data.pop(); + return data; + } +} + +// ---- +// test() -> 0x20, 33, 0x303030303030303030303030303030303030303030303030303030303030303, 0x0300000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/byte_array_push.sol b/test/libsolidity/semanticTests/extracted/byte_array_push.sol new file mode 100644 index 000000000000..67ed87b691e1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_push.sol @@ -0,0 +1,18 @@ +contract c { + bytes data; + + function test() public returns (bool x) { + data.push(0x05); + if (data.length != 1) return true; + if (data[0] != 0x05) return true; + data.push(0x04); + if (data[1] != 0x04) return true; + data.push(0x03); + uint256 l = data.length; + if (data[2] != 0x03) return true; + if (l != 0x03) return true; + } +} + +// ---- +// test() -> false diff --git a/test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol b/test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol new file mode 100644 index 000000000000..ceecf6726c27 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol @@ -0,0 +1,18 @@ +// Tests transition between short and long encoding +contract c { + bytes data; + + function test() public returns (uint256) { + for (uint8 i = 1; i < 40; i++) { + data.push(bytes1(i)); + if (data.length != i) return 0x1000 + i; + if (data[data.length - 1] != bytes1(i)) return i; + } + for (uint8 i = 1; i < 40; i++) + if (data[i - 1] != bytes1(i)) return 0x1000000 + i; + return 0; + } +} + +// ---- +// test() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol b/test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol new file mode 100644 index 000000000000..3d94e4333fe8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol @@ -0,0 +1,19 @@ +contract C { + function f(uint256 x) public returns (uint256 a) { + assembly { + a := byte(x, 31) + } + } + + function g(uint256 x) public returns (uint256 a) { + assembly { + a := byte(31, x) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 2 -> 0 +// g(uint256): 2 -> 2 diff --git a/test/libsolidity/semanticTests/extracted/bytes_delete_element.sol b/test/libsolidity/semanticTests/extracted/bytes_delete_element.sol new file mode 100644 index 000000000000..e3a8ec19d196 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bytes_delete_element.sol @@ -0,0 +1,19 @@ +contract c { + bytes data; + + function test1() external returns (bool) { + data = new bytes(100); + for (uint256 i = 0; i < data.length; i++) data[i] = bytes1(uint8(i)); + delete data[94]; + delete data[96]; + delete data[98]; + return + data[94] == 0 && + uint8(data[95]) == 95 && + data[96] == 0 && + uint8(data[97]) == 97; + } +} + +// ---- +// test1() -> true diff --git a/test/libsolidity/semanticTests/extracted/bytes_length_member.sol b/test/libsolidity/semanticTests/extracted/bytes_length_member.sol new file mode 100644 index 000000000000..8c48720175a0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bytes_length_member.sol @@ -0,0 +1,17 @@ +contract c { + function set() public returns (bool) { + data = msg.data; + return true; + } + + function getLength() public returns (uint256) { + return data.length; + } + + bytes data; +} + +// ---- +// getLength() -> 0 +// set(): 1, 2 -> true +// getLength() -> 68 diff --git a/test/libsolidity/semanticTests/extracted/call_function_returning_function.sol b/test/libsolidity/semanticTests/extracted/call_function_returning_function.sol new file mode 100644 index 000000000000..5d93ba0ee7dd --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/call_function_returning_function.sol @@ -0,0 +1,28 @@ +contract test { + function f0() public returns (uint) { + return 2; + } + + function f1() internal returns (function() internal returns (uint)) { + return f0; + } + + function f2() internal returns (function() internal returns (function () internal returns (uint))) { + return f1; + } + + function f3() internal returns (function() internal returns (function () internal returns (function () internal returns (uint)))) { + return f2; + } + + function f() public returns (uint) { + function() internal returns(function() internal returns(function() internal returns(function() internal returns(uint)))) x; + x = f3; + return x()()()(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/calldata_array.sol b/test/libsolidity/semanticTests/extracted/calldata_array.sol new file mode 100644 index 000000000000..c9c6dbda0981 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array.sol @@ -0,0 +1,16 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[2] calldata s) + external + pure + returns (uint256 a, uint256 b) + { + a = s[0]; + b = s[1]; + } +} + +// ---- +// f(uint256[2]): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol new file mode 100644 index 000000000000..d643d39739f0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol @@ -0,0 +1,21 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][] calldata a) external returns (uint256) { + return 42; + } + + function g(uint256[][] calldata a) external returns (uint256) { + a[0]; + return 42; + } +} + +// ---- +// f(uint256[][]): 0x20, 0x0 -> 42 # valid access stub # +// f(uint256[][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # +// f(uint256[][]): 0x20, 0x1, 0x20 -> 42 # invalid on outer access # +// g(uint256[][]): 0x20, 0x1, 0x20 -> FAILURE +// f(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x42 -> 42 # invalid on inner access # +// g(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x42 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol new file mode 100644 index 000000000000..3efd177b2ca4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol @@ -0,0 +1,30 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][1][] calldata a) external returns (uint256) { + return 42; + } + + function g(uint256[][1][] calldata a) external returns (uint256) { + a[0]; + return 42; + } + + function h(uint256[][1][] calldata a) external returns (uint256) { + a[0][0]; + return 42; + } +} + +// ---- +// f(uint256[][1][]): 0x20, 0x0 -> 42 # valid access stub # +// f(uint256[][1][]): 0x20, 0x1 -> FAILURE # invalid on argument decoding # +// f(uint256[][1][]): 0x20, 0x1, 0x20 -> 42 # invalid on outer access # +// g(uint256[][1][]): 0x20, 0x1, 0x20 -> FAILURE +// f(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> 42 # invalid on inner access # +// g(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> 42 +// h(uint256[][1][]): 0x20, 0x1, 0x20, 0x20 -> FAILURE +// f(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> 42 +// g(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> 42 +// h(uint256[][1][]): 0x20, 0x1, 0x20, 0x20, 0x1 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol b/test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol new file mode 100644 index 000000000000..33311226500a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S[] calldata s) + external + pure + returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) + { + l = s.length; + a = s[0].a; + b = s[0].b; + c = s[1].a; + d = s[1].b; + } +} + +// ---- +// f((uint256,uint256)[]): 0x20, 0x2, 0x1, 0x2, 0x3, 0x4 -> 2, 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol b/test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol new file mode 100644 index 000000000000..f408746f5f15 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol @@ -0,0 +1,25 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S[] calldata s) + external + pure + returns (uint256 l, uint256 a, uint256 b, uint256 c, uint256 d) + { + S[] memory m = s; + l = m.length; + a = m[0].a; + b = m[0].b; + c = m[1].a; + d = m[1].b; + } +} + +// ---- +// f((uint256,uint256)[]): 0x20, 0x2, 0x1, 0x2, 0x3, 0x4 -> 2, 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol b/test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol new file mode 100644 index 000000000000..7b225a33b13a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint256[][] calldata a) + external + returns (uint256, uint256[] memory) + { + uint256[] memory m = a[0]; + return (a.length, m); + } +} + +// ---- +// f(uint256[][]): 0x20, 0x1, 0x20, 0x2, 0x17, 0x2a -> 0x1, 0x40, 0x2, 0x17, 0x2a diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct.sol b/test/libsolidity/semanticTests/extracted/calldata_struct.sol new file mode 100644 index 000000000000..a7ecf2bd02d6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_struct.sol @@ -0,0 +1,17 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S calldata s) external pure returns (uint256 a, uint256 b) { + a = s.a; + b = s.b; + } +} + +// ---- +// f((uint256,uint256)): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol b/test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol new file mode 100644 index 000000000000..c3b8249e8f61 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol @@ -0,0 +1,20 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(uint256 a, S calldata s, uint256 b) + external + pure + returns (uint256, uint256, uint256, uint256) + { + return (a, s.a, s.b, b); + } +} + +// ---- +// f(uint256,(uint256,uint256),uint256): 1, 2, 3, 4 -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol b/test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol new file mode 100644 index 000000000000..3e8613fad9b5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256[2] b; + uint256 c; + } + + function f(S calldata s) + external + pure + returns (uint256 a, uint256 b0, uint256 b1, uint256 c) + { + a = s.a; + b0 = s.b[0]; + b1 = s.b[1]; + c = s.c; + } +} + +// ---- +// f((uint256,uint256[2],uint256)): 42, 1, 2, 23 -> 42, 1, 2, 23 diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol new file mode 100644 index 000000000000..db8171a202d0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol @@ -0,0 +1,17 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint256 a; + uint256 b; + } + + function f(S calldata s) external pure returns (uint256, uint256) { + S memory m = s; + return (m.a, m.b); + } +} + +// ---- +// f((uint256,uint256)): 42, 23 -> 42, 23 diff --git a/test/libsolidity/semanticTests/extracted/calldata_structs.sol b/test/libsolidity/semanticTests/extracted/calldata_structs.sol new file mode 100644 index 000000000000..4139c1073b65 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_structs.sol @@ -0,0 +1,27 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + } + + function f(S1 calldata s1, S2 calldata s2, S1 calldata s3) + external + pure + returns (uint256 a, uint256 b, uint256 c, uint256 d, uint256 e) + { + a = s1.a; + b = s1.b; + c = s2.a; + d = s3.a; + e = s3.b; + } +} + +// ---- +// f((uint256,uint256),(uint256),(uint256,uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol b/test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol new file mode 100644 index 000000000000..2ccfc064c81d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol @@ -0,0 +1,28 @@ +abstract contract D { + function g() public virtual; +} + + +contract C { + D d = D(0x1212); + + function f() public returns (uint256) { + d.g(); + return 7; + } + + function g() public returns (uint256) { + d.g.gas(200)(); + return 7; + } + + function h() public returns (uint256) { + address(d).call(""); // this does not throw (low-level) + return 7; + } +} + +// ---- +// f() -> FAILURE +// g() -> FAILURE +// h() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol new file mode 100644 index 000000000000..e1cab8fe8af4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol @@ -0,0 +1,17 @@ +contract C { + function intern() public returns (uint256) { + function (uint) internal returns (uint) x; + x(2); + return 7; + } + + function extern() public returns (uint256) { + function (uint) external returns (uint) x; + x(2); + return 7; + } +} + +// ---- +// intern() -> FAILURE # This should throw exceptions # +// extern() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol new file mode 100644 index 000000000000..0ae431b24b83 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol @@ -0,0 +1,20 @@ +contract C { + function() returns (uint256) internal x; + int256 mutex; + + function t() public returns (uint256) { + if (mutex > 0) { + assembly { + mstore(0, 7) + return(0, 0x20) + } + } + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + x(); + return 2; + } +} + +// ---- +// t() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol new file mode 100644 index 000000000000..26a2a79f4c5c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol @@ -0,0 +1,20 @@ +contract C { + int256 mutex; + + function t() public returns (uint256) { + if (mutex > 0) { + assembly { + mstore(0, 7) + return(0, 0x20) + } + } + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + function() internal returns (uint)[200] memory x; + x[0](); + return 2; + } +} + +// ---- +// t() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol b/test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol new file mode 100644 index 000000000000..074b3ff6b49b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol @@ -0,0 +1,33 @@ +contract C { + function f() public pure returns (address r) { + bytes21 x = 0x1122334455667788990011223344556677889900ff; + bytes20 y; + assembly { + y := x + } + address z = address(y); + assembly { + r := z + } + require(z == 0x1122334455667788990011223344556677889900); + } + + function g() public pure returns (address payable r) { + bytes21 x = 0x1122334455667788990011223344556677889900ff; + bytes20 y; + assembly { + y := x + } + address payable z = address(y); + assembly { + r := z + } + require(z == 0x1122334455667788990011223344556677889900); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1122334455667788990011223344556677889900 +// g() -> 0x1122334455667788990011223344556677889900 diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol new file mode 100644 index 000000000000..dc7c7f8905ab --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (bytes32 r) { + bytes4 x = 0xffffffff; + bytes2 y = bytes2(x); + assembly { + r := y + } + // At this point, r and y both store four bytes, but + // y is properly cleaned before the equality check + require(y == bytes2(0xffff)); + } +} + +// ---- +// f() -> "\xff\xff\xff\xff" diff --git a/test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol b/test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol new file mode 100644 index 000000000000..c1901c73839d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol @@ -0,0 +1,13 @@ +contract C { + function test() public returns (uint256, uint256) { + uint32 a = 0xffffffff; + uint16 x = uint16(a); + uint16 y = x; + x /= 0x100; + y = y / 0x100; + return (x, y); + } +} + +// ---- +// test() -> 0xff, 0xff diff --git a/test/libsolidity/semanticTests/extracted/code_access_content.sol b/test/libsolidity/semanticTests/extracted/code_access_content.sol new file mode 100644 index 000000000000..2c115d6c8dae --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/code_access_content.sol @@ -0,0 +1,42 @@ +contract D { + bytes32 public x; + + constructor() public { + bytes32 codeHash; + assembly { + let size := codesize() + codecopy(mload(0x40), 0, size) + codeHash := keccak256(mload(0x40), size) + } + x = codeHash; + } +} + + +contract C { + function testRuntime() public returns (bool) { + D d = new D(); + bytes32 runtimeHash = keccak256(type(D).runtimeCode); + bytes32 otherHash; + uint256 size; + assembly { + size := extcodesize(d) + extcodecopy(d, mload(0x40), 0, size) + otherHash := keccak256(mload(0x40), size) + } + require(size == type(D).runtimeCode.length); + require(runtimeHash == otherHash); + return true; + } + + function testCreation() public returns (bool) { + D d = new D(); + bytes32 creationHash = keccak256(type(D).creationCode); + require(creationHash == d.x()); + return true; + } +} + +// ---- +// testRuntime() -> true +// testCreation() -> true diff --git a/test/libsolidity/semanticTests/extracted/code_access_create.sol b/test/libsolidity/semanticTests/extracted/code_access_create.sol new file mode 100644 index 000000000000..3fbcf6132e6d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/code_access_create.sol @@ -0,0 +1,26 @@ +contract D { + uint256 x; + + constructor() public { + x = 7; + } + + function f() public view returns (uint256) { + return x; + } +} + + +contract C { + function test() public returns (uint256) { + bytes memory c = type(D).creationCode; + D d; + assembly { + d := create(0, add(c, 0x20), mload(c)) + } + return d.f(); + } +} + +// ---- +// test() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/code_access_padding.sol b/test/libsolidity/semanticTests/extracted/code_access_padding.sol new file mode 100644 index 000000000000..ecad28a16580 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/code_access_padding.sol @@ -0,0 +1,19 @@ +contract D { + function f() public pure returns (uint256) { + return 7; + } +} + + +contract C { + function diff() public pure returns (uint256 remainder) { + bytes memory a = type(D).creationCode; + bytes memory b = type(D).runtimeCode; + assembly { + remainder := mod(sub(b, a), 0x20) + } + } +} + +// ---- +// diff() -> 0 # This checks that the allocation function pads to multiples of 32 bytes # diff --git a/test/libsolidity/semanticTests/extracted/constant_string.sol b/test/libsolidity/semanticTests/extracted/constant_string.sol new file mode 100644 index 000000000000..56cbf982d120 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constant_string.sol @@ -0,0 +1,22 @@ +contract C { + bytes constant a = "\x03\x01\x02"; + bytes constant b = hex"030102"; + string constant c = "hello"; + + function f() public returns (bytes memory) { + return a; + } + + function g() public returns (bytes memory) { + return b; + } + + function h() public returns (bytes memory) { + return bytes(c); + } +} + +// ---- +// f() -> 0x20, 3, "\x03\x01\x02" +// g() -> 0x20, 3, "\x03\x01\x02" +// h() -> 0x20, 5, "hello" diff --git a/test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol new file mode 100644 index 000000000000..017de5d7b32a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol @@ -0,0 +1,14 @@ +contract C { + uint256 constant LEN = 3; + uint256[LEN] public a; + + constructor(uint256[LEN] memory _a) public { + a = _a; + } +} + +// ---- +// constructor(): 1, 2, 3 -> +// a(uint256): 0 -> 1 +// a(uint256): 1 -> 2 +// a(uint256): 2 -> 3 diff --git a/test/libsolidity/semanticTests/extracted/constant_variables.sol b/test/libsolidity/semanticTests/extracted/constant_variables.sol new file mode 100644 index 000000000000..98b4773c79ba --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constant_variables.sol @@ -0,0 +1,11 @@ +contract Foo { + uint256 constant x = 56; + enum ActionChoices {GoLeft, GoRight, GoStraight, Sit} + ActionChoices constant choices = ActionChoices.GoLeft; + bytes32 constant st = "abc\x00\xff__"; +} + +// ==== +// compileViaYul: also +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol b/test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol new file mode 100644 index 000000000000..9ff75fad6064 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol @@ -0,0 +1,12 @@ +contract c { + enum Truth {False, True} + + function test() public returns (uint256) { + return uint256(Truth(uint8(0x701))); + } +} + +// ==== +// compileViaYul: also +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol b/test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol new file mode 100644 index 000000000000..ec30bacf6c16 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol @@ -0,0 +1,22 @@ +contract Main { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + +// ---- +// constructor(): "abc", true +// getFlag() -> true +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol b/test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol new file mode 100644 index 000000000000..756478e342d0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol @@ -0,0 +1,38 @@ +contract Helper { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + + +contract Main { + Helper h; + + constructor() public { + h = new Helper("abc", true); + } + + function getFlag() public returns (bool ret) { + return h.getFlag(); + } + + function getName() public returns (bytes3 ret) { + return h.getName(); + } +} + +// ---- +// getFlag() -> true +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol new file mode 100644 index 000000000000..10243f8979b2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol @@ -0,0 +1,16 @@ +contract C { + uint256 public a; + uint256[3] public b; + + constructor(uint256 _a, uint256[3] memory _b) public { + a = _a; + b = _b; + } +} + +// ---- +// constructor(): 1, 2, 3, 4 -> +// a() -> 1 +// b(uint256): 0 -> 2 +// b(uint256): 1 -> 3 +// b(uint256): 2 -> 4 diff --git a/test/libsolidity/semanticTests/extracted/continue_in_modifier.sol b/test/libsolidity/semanticTests/extracted/continue_in_modifier.sol new file mode 100644 index 000000000000..1db0f2e9ff69 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/continue_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + if (i % 2 == 1) continue; + _; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 5 diff --git a/test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol b/test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol new file mode 100644 index 000000000000..f1220d351e4c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol @@ -0,0 +1,20 @@ +contract A { + function f() public { + new B(); + } +} + + +contract B { + function f() public {} +} + + +contract C { + function f() public { + new B(); + } +} + +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol b/test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol new file mode 100644 index 000000000000..eba61ad1afa1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol @@ -0,0 +1,18 @@ +contract C { + function() internal returns (uint)[] x; + function() internal returns (uint)[] y; + + function test() public returns (uint256) { + x = new function() internal returns (uint)[](10); + x[9] = a; + y = x; + return y[9](); + } + + function a() public returns (uint256) { + return 7; + } +} + +// ---- +// test() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol new file mode 100644 index 000000000000..076cbbf69a77 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol @@ -0,0 +1,22 @@ +contract C { + function() internal returns (uint)[20] x; + int256 mutex; + + function one() public returns (uint256) { + function() internal returns (uint)[20] memory xmem; + x = xmem; + return 3; + } + + function two() public returns (uint256) { + if (mutex > 0) return 7; + mutex = 1; + // If this test fails, it might re-execute this function. + x[0](); + return 2; + } +} + +// ---- +// one() -> 3 +// two() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol b/test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol new file mode 100644 index 000000000000..fdd7aa32ebbf --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol @@ -0,0 +1,15 @@ +contract C { + function f() public returns (uint256 r) { + uint256; + uint256; + uint256; + uint256; + int256 x = -7; + return uint256(x); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> -7 diff --git a/test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol b/test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol new file mode 100644 index 000000000000..7c2ccde6e28e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256) { + uint256[][] memory a = new uint256[][](0); + return 7; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/create_memory_array.sol b/test/libsolidity/semanticTests/extracted/create_memory_array.sol new file mode 100644 index 000000000000..fd4fe943cb65 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/create_memory_array.sol @@ -0,0 +1,21 @@ +contract C { + struct S { + uint256[2] a; + bytes b; + } + + function f() public returns (bytes1, uint256, uint256, bytes1) { + bytes memory x = new bytes(200); + x[199] = "A"; + uint256[2][] memory y = new uint256[2][](300); + y[203][1] = 8; + S[] memory z = new S[](180); + z[170].a[1] = 4; + z[170].b = new bytes(102); + z[170].b[99] = "B"; + return (x[199], y[203][1], z[170].a[1], z[170].b[99]); + } +} + +// ---- +// f() -> "A", 8, 4, "B" diff --git a/test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol b/test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol new file mode 100644 index 000000000000..731fb43128b7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol @@ -0,0 +1,34 @@ +contract C { + function f() public returns (uint256) { + uint256[][] memory x = new uint256[][](42); + assert(x[0].length == 0); + x[0] = new uint256[](1); + x[0][0] = 1; + assert(x[4].length == 0); + x[4] = new uint256[](1); + x[4][0] = 2; + assert(x[10].length == 0); + x[10] = new uint256[](1); + x[10][0] = 44; + uint256[][] memory y = new uint256[][](24); + assert(y[0].length == 0); + y[0] = new uint256[](1); + y[0][0] = 1; + assert(y[4].length == 0); + y[4] = new uint256[](1); + y[4][0] = 2; + assert(y[10].length == 0); + y[10] = new uint256[](1); + y[10][0] = 88; + if ( + (x[0][0] == y[0][0]) && + (x[4][0] == y[4][0]) && + (x[10][0] == 44) && + (y[10][0] == 88) + ) return 7; + return 0; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/cross_contract_types.sol b/test/libsolidity/semanticTests/extracted/cross_contract_types.sol new file mode 100644 index 000000000000..47842cc030bb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cross_contract_types.sol @@ -0,0 +1,17 @@ +contract Lib { + struct S { + uint256 a; + uint256 b; + } +} + + +contract Test { + function f() public returns (uint256 r) { + Lib.S memory x = Lib.S({a: 2, b: 3}); + r = x.b; + } +} + +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/decayed_tuple.sol b/test/libsolidity/semanticTests/extracted/decayed_tuple.sol new file mode 100644 index 000000000000..b00942cb3225 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/decayed_tuple.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (uint256) { + uint256 x = 1; + (x) = 2; + return x; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol b/test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol new file mode 100644 index 000000000000..316b8d9efd1e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol @@ -0,0 +1,20 @@ +// Test for a bug where we did not increment the counter properly while deleting a dynamic array. +contract C { + struct S { + uint256 x; + uint256[] y; + } + S[] data; + + function f() public returns (bool) { + S storage s1 = data.push(); + s1.x = 2**200; + S storage s2 = data.push(); + s2.x = 2**200; + delete data; + return true; + } +} + +// ---- +// f() -> true # This code interprets x as an array length and thus will go out of gas. neither of the two should throw due to out-of-bounds access # diff --git a/test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol b/test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol new file mode 100644 index 000000000000..5628501d9a2d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol @@ -0,0 +1,21 @@ +contract B { + function f() public returns (uint256) { + return 10; + } +} + + +contract C is B { + function f(uint256 i) public returns (uint256) { + return 2 * i; + } + + function g() public returns (uint256) { + return f(1); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol b/test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol new file mode 100644 index 000000000000..949024f43e8f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol @@ -0,0 +1,29 @@ +contract A { + function f(uint256 a) public returns (uint256) { + return 2 * a; + } +} + + +contract B { + function f() public returns (uint256) { + return 10; + } +} + + +contract C is A, B { + function g() public returns (uint256) { + return f(); + } + + function h() public returns (uint256) { + return f(1); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 10 +// h() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/destructuring_assignment.sol b/test/libsolidity/semanticTests/extracted/destructuring_assignment.sol new file mode 100644 index 000000000000..0c8dc3835ff1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/destructuring_assignment.sol @@ -0,0 +1,36 @@ +contract C { + uint256 x = 7; + bytes data; + uint256[] y; + uint256[] arrayData; + + function returnsArray() public returns (uint256[] memory) { + arrayData = new uint256[](9); + arrayData[2] = 5; + arrayData[7] = 4; + return arrayData; + } + + function f(bytes memory s) public returns (uint256) { + uint256 loc; + uint256[] memory memArray; + (loc, x, y, data, arrayData[3]) = (8, 4, returnsArray(), s, 2); + if (loc != 8) return 1; + if (x != 4) return 2; + if (y.length != 9) return 3; + if (y[2] != 5) return 4; + if (y[7] != 4) return 5; + if (data.length != s.length) return 6; + if (data[3] != s[3]) return 7; + if (arrayData[3] != 2) return 8; + (memArray, loc) = (arrayData, 3); + if (loc != 3) return 9; + if (memArray.length != arrayData.length) return 10; + bytes memory memBytes; + (x, memBytes, y[2], , ) = (456, s, 789, 101112, 131415); + if (x != 456 || memBytes.length != s.length || y[2] != 789) return 11; + } +} + +// ---- +// f(bytes): 0x20, 0x5, "abcde" -> 0 diff --git a/test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol b/test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol new file mode 100644 index 000000000000..127320fc676e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol @@ -0,0 +1,15 @@ +contract C { + function div(uint256 a, uint256 b) public returns (uint256) { + return a / b; + } + + function mod(uint256 a, uint256 b) public returns (uint256) { + return a % b; + } +} + +// ---- +// div(uint256,uint256): 7, 2 -> 3 +// div(uint256,uint256): 7, 0 -> FAILURE # throws # +// mod(uint256,uint256): 7, 2 -> 1 +// mod(uint256,uint256): 7, 0 -> FAILURE # throws # diff --git a/test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol b/test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol new file mode 100644 index 000000000000..6680ec5d910a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol @@ -0,0 +1,53 @@ +contract c { + struct Data { + uint256 x; + uint256 y; + } + Data[] data; + uint256[] ids; + + function setIDStatic(uint256 id) public { + ids[2] = id; + } + + function setID(uint256 index, uint256 id) public { + ids[index] = id; + } + + function setData(uint256 index, uint256 x, uint256 y) public { + data[index].x = x; + data[index].y = y; + } + + function getID(uint256 index) public returns (uint256) { + return ids[index]; + } + + function getData(uint256 index) public returns (uint256 x, uint256 y) { + x = data[index].x; + y = data[index].y; + } + + function getLengths() public returns (uint256 l1, uint256 l2) { + l1 = data.length; + l2 = ids.length; + } + + function setLengths(uint256 l1, uint256 l2) public { + while (data.length < l1) data.push(); + while (ids.length < l2) ids.push(); + } +} + +// ---- +// getLengths() -> 0, 0 +// setLengths(uint256,uint256): 48, 49 -> +// getLengths() -> 48, 49 +// setIDStatic(uint256): 11 -> +// getID(uint256): 2 -> 11 +// setID(uint256,uint256): 7, 8 -> +// getID(uint256): 7 -> 8 +// setData(uint256,uint256,uint256): 7, 8, 9 -> +// setData(uint256,uint256,uint256): 8, 10, 11 -> +// getData(uint256): 7 -> 8, 9 +// getData(uint256): 8 -> 10, 11 diff --git a/test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol new file mode 100644 index 000000000000..b2c6893a5340 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol @@ -0,0 +1,34 @@ +contract c { + uint256[] data; + + function enlarge(uint256 amount) public returns (uint256) { + while (data.length < amount) data.push(); + return data.length; + } + + function set(uint256 index, uint256 value) public returns (bool) { + data[index] = value; + return true; + } + + function get(uint256 index) public returns (uint256) { + return data[index]; + } + + function length() public returns (uint256) { + return data.length; + } +} + +// ==== +// compileViaYul: also +// ---- +// length() -> 0 +// get(uint256): 3 -> FAILURE +// enlarge(uint256): 4 -> 4 +// length() -> 4 +// set(uint256,uint256): 3, 4 -> true +// get(uint256): 3 -> 4 +// length() -> 4 +// set(uint256,uint256): 4, 8 -> FAILURE +// length() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol b/test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol new file mode 100644 index 000000000000..d1ea9ab34f0b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol @@ -0,0 +1,10 @@ +contract test { + function f(uint256 k) public returns (uint256) { + return k; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 9 -> 9 diff --git a/test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol b/test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol new file mode 100644 index 000000000000..fd4c96ce7658 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol @@ -0,0 +1,31 @@ +contract test { + enum ActionChoices {GoLeft, GoRight, GoStraight} + + constructor() public {} + + function getChoiceExp(uint256 x) public returns (uint256 d) { + choice = ActionChoices(x); + d = uint256(choice); + } + + function getChoiceFromSigned(int256 x) public returns (uint256 d) { + choice = ActionChoices(x); + d = uint256(choice); + } + + function getChoiceFromNegativeLiteral() public returns (uint256 d) { + choice = ActionChoices(-1); + d = uint256(choice); + } + + ActionChoices choice; +} + +// ==== +// compileViaYul: also +// ---- +// getChoiceExp(uint256): 3 -> FAILURE # These should throw # +// getChoiceFromSigned(int256): -1 -> FAILURE +// getChoiceFromNegativeLiteral() -> FAILURE +// getChoiceExp(uint256): 2 -> 2 # These should work # +// getChoiceExp(uint256): 0 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol b/test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol new file mode 100644 index 000000000000..2192dabf32bc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol @@ -0,0 +1,19 @@ +contract A { + constructor() public { + address(this).call("123"); + } +} + + +contract B { + uint256 public test = 1; + + function testIt() public { + A a = new A(); + ++test; + } +} + +// ---- +// testIt() -> +// test() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol b/test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol new file mode 100644 index 000000000000..af14b48b4016 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol @@ -0,0 +1,19 @@ +contract A { + uint256[3] arr; + bool public test = false; + + function getElement(uint256 i) public returns (uint256) { + return arr[i]; + } + + function testIt() public returns (bool) { + uint256 i = this.getElement(5); + test = true; + return true; + } +} + +// ---- +// test() -> false +// testIt() -> FAILURE +// test() -> false diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup.sol b/test/libsolidity/semanticTests/extracted/exp_cleanup.sol new file mode 100644 index 000000000000..a81e2755ef8e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/exp_cleanup.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure returns (uint8 x) { + uint8 y = uint8(2)**uint8(8); + return 0**y; + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol b/test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol new file mode 100644 index 000000000000..a9b5e81b54fb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure returns (uint8 x) { + return uint8(0)**uint8(uint8(2)**uint8(8)); + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol b/test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol new file mode 100644 index 000000000000..4f817d18622a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure returns (uint8 x) { + return uint8(0x166)**uint8(uint8(2)**uint8(8)); + } +} + +// ---- +// f() -> 0x1 diff --git a/test/libsolidity/semanticTests/extracted/explicit_base_class.sol b/test/libsolidity/semanticTests/extracted/explicit_base_class.sol new file mode 100644 index 000000000000..44553b3f1adb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/explicit_base_class.sol @@ -0,0 +1,27 @@ +contract BaseBase { + function g() public virtual returns (uint256 r) { + return 1; + } +} + + +contract Base is BaseBase { + function g() public virtual override returns (uint256 r) { + return 2; + } +} + + +contract Derived is Base { + function f() public returns (uint256 r) { + return BaseBase.g(); + } + + function g() public override returns (uint256 r) { + return 3; + } +} + +// ---- +// g() -> 3 +// f() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/external_function.sol b/test/libsolidity/semanticTests/extracted/external_function.sol new file mode 100644 index 000000000000..3625864477f0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/external_function.sol @@ -0,0 +1,18 @@ +contract c { + function f(uint256 a) public returns (uint256) { + return a; + } + + function test(uint256 a, uint256 b) + external + returns (uint256 r_a, uint256 r_b) + { + r_a = f(a + 7); + r_b = b; + } +} + +// ==== +// compileViaYul: also +// ---- +// test(uint256,uint256): 2, 3 -> 9, 3 diff --git a/test/libsolidity/semanticTests/extracted/external_public_override.sol b/test/libsolidity/semanticTests/extracted/external_public_override.sol new file mode 100644 index 000000000000..7909f8e324a3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/external_public_override.sol @@ -0,0 +1,22 @@ +contract A { + function f() external virtual returns (uint256) { + return 1; + } +} + + +contract B is A { + function f() public override returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return f(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 2 +// g() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/external_types_in_calls.sol b/test/libsolidity/semanticTests/extracted/external_types_in_calls.sol new file mode 100644 index 000000000000..9906bd52bc33 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/external_types_in_calls.sol @@ -0,0 +1,28 @@ +contract C1 { + C1 public bla; + + constructor(C1 x) public { + bla = x; + } +} + + +contract C { + function test() public returns (C1 x, C1 y) { + C1 c = new C1(C1(9)); + x = c.bla(); + y = this.t1(C1(7)); + } + + function t1(C1 a) public returns (C1) { + return a; + } + + function t2() public returns (C1) { + return C1(9); + } +} + +// ---- +// test() -> 9, 7 +// t2() -> 9 diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol new file mode 100644 index 000000000000..61d1a33f55d2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol @@ -0,0 +1,21 @@ +contract A { + function f(uint16 input) public pure returns (uint16[5] memory arr) { + arr[0] = input; + arr[1] = ++input; + arr[2] = ++input; + arr[3] = ++input; + arr[4] = ++input; + } +} + + +contract B { + function f() public returns (uint16[5] memory res, uint16[5] memory res2) { + A a = new A(); + res = a.f(2); + res2 = a.f(1000); + } +} + +// ---- +// f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004 diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol new file mode 100644 index 000000000000..ff13db5be126 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol @@ -0,0 +1,14 @@ +contract Creator { + uint256 public r; + address public ch; + + constructor(address[3] memory s, uint256 x) public { + r = x; + ch = s[2]; + } +} + +// ---- +// constructor(): 1, 2, 3, 4 -> +// r() -> 4 +// ch() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol b/test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol new file mode 100644 index 000000000000..7a6afbae7de3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol @@ -0,0 +1,10 @@ +contract C { + bytes1 a; + + function f(bytes32 x) public returns (uint256, uint256, uint256) { + return (x.length, bytes16(uint128(2)).length, a.length + 7); + } +} + +// ---- +// f(bytes32): "789" -> 32, 16, 8 diff --git a/test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol new file mode 100644 index 000000000000..06246cdc6160 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol @@ -0,0 +1,28 @@ +contract c { + uint256[4] data; + + function set(uint256 index, uint256 value) public returns (bool) { + data[index] = value; + return true; + } + + function get(uint256 index) public returns (uint256) { + return data[index]; + } + + function length() public returns (uint256) { + return data.length; + } +} + +// ==== +// compileViaYul: also +// ---- +// length() -> 4 +// set(uint256,uint256): 3, 4 -> true +// set(uint256,uint256): 4, 5 -> FAILURE +// set(uint256,uint256): 400, 5 -> FAILURE +// get(uint256): 3 -> 4 +// get(uint256): 4 -> FAILURE +// get(uint256): 400 -> FAILURE +// length() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol b/test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol new file mode 100644 index 000000000000..8309615a5c22 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol @@ -0,0 +1,10 @@ +contract test { + function f() public returns (bool) { + int256 x = -2**255; + assert(-x == x); + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol b/test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol new file mode 100644 index 000000000000..64f8c74028fb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol @@ -0,0 +1,45 @@ +contract D { + function f(function() external returns (function() external returns (uint))[] memory x) + public returns (function() external returns (uint)[3] memory r) { + r[0] = x[0](); + r[1] = x[1](); + r[2] = x[2](); + } +} + + +contract C { + function test() public returns (uint256, uint256, uint256) { + function() external returns (function() external returns (uint))[] memory x = + new function() external returns (function() external returns (uint))[](10); + for (uint256 i = 0; i < x.length; i++) x[i] = this.h; + x[0] = this.htwo; + function() external returns (uint)[3] memory y = (new D()).f(x); + return (y[0](), y[1](), y[2]()); + } + + function e() public returns (uint256) { + return 5; + } + + function f() public returns (uint256) { + return 6; + } + + function g() public returns (uint256) { + return 7; + } + + uint256 counter; + + function h() public returns (function() external returns (uint)) { + return counter++ == 0 ? this.f : this.g; + } + + function htwo() public returns (function() external returns (uint)) { + return this.e; + } +} + +// ---- +// test() -> 5, 6, 7 diff --git a/test/libsolidity/semanticTests/extracted/function_delete_stack.sol b/test/libsolidity/semanticTests/extracted/function_delete_stack.sol new file mode 100644 index 000000000000..96a66fce2969 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_delete_stack.sol @@ -0,0 +1,16 @@ +contract C { + function a() public returns (uint256) { + return 7; + } + + function test() public returns (uint256) { + function() returns (uint256) y = a; + delete y; + y(); + } +} + +// ==== +// compileViaYul: also +// ---- +// test() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/function_delete_storage.sol b/test/libsolidity/semanticTests/extracted/function_delete_storage.sol new file mode 100644 index 000000000000..6c7ecf4f693c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_delete_storage.sol @@ -0,0 +1,27 @@ +contract C { + function a() public returns (uint256) { + return 7; + } + + function() returns (uint256) internal y; + + function set() public returns (uint256) { + y = a; + return y(); + } + + function d() public returns (uint256) { + delete y; + return 1; + } + + function ca() public returns (uint256) { + return y(); + } +} + +// ---- +// set() -> 7 +// ca() -> 7 +// d() -> 1 +// ca() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/function_memory_array.sol b/test/libsolidity/semanticTests/extracted/function_memory_array.sol new file mode 100644 index 000000000000..cc6b3cf468e3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_memory_array.sol @@ -0,0 +1,40 @@ +contract C { + function a(uint256 x) public returns (uint256) { + return x + 1; + } + + function b(uint256 x) public returns (uint256) { + return x + 2; + } + + function c(uint256 x) public returns (uint256) { + return x + 3; + } + + function d(uint256 x) public returns (uint256) { + return x + 5; + } + + function e(uint256 x) public returns (uint256) { + return x + 8; + } + + function test(uint256 x, uint256 i) public returns (uint256) { + function(uint) internal returns (uint)[] memory arr = + new function(uint) internal returns (uint)[](10); + arr[0] = a; + arr[1] = b; + arr[2] = c; + arr[3] = d; + arr[4] = e; + return arr[i](x); + } +} + +// ---- +// test(uint256,uint256): 10, 0 -> 11 +// test(uint256,uint256): 10, 1 -> 12 +// test(uint256,uint256): 10, 2 -> 13 +// test(uint256,uint256): 10, 3 -> 15 +// test(uint256,uint256): 10, 4 -> 18 +// test(uint256,uint256): 10, 5 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/function_modifier.sol b/test/libsolidity/semanticTests/extracted/function_modifier.sol new file mode 100644 index 000000000000..fcb8f64a23f2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier.sol @@ -0,0 +1,13 @@ +contract C { + function getOne() public payable nonFree returns (uint256 r) { + return 1; + } + + modifier nonFree { + if (msg.value > 0) _; + } +} + +// ---- +// getOne() -> 0 +// getOne(), 1 wei -> 1 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol b/test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol new file mode 100644 index 000000000000..f4a73ebebc8a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol @@ -0,0 +1,49 @@ +contract A { + uint256 data; + + constructor() public mod1 { + f1(); + } + + function f1() public mod2 { + data |= 0x1; + } + + function f2() public { + data |= 0x20; + } + + function f3() public virtual {} + + modifier mod1 virtual { + f2(); + _; + } + modifier mod2 { + f3(); + if (false) _; + } + + function getData() public returns (uint256 r) { + return data; + } +} + + +contract C is A { + modifier mod1 override { + f4(); + _; + } + + function f3() public override { + data |= 0x300; + } + + function f4() public { + data |= 0x4000; + } +} + +// ---- +// getData() -> 0x4300 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol b/test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol new file mode 100644 index 000000000000..ac99b0cf74f8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol @@ -0,0 +1,27 @@ +contract A { + uint256 data; + + constructor() public mod1 { + data |= 2; + } + + modifier mod1 virtual { + data |= 1; + _; + } + + function getData() public returns (uint256 r) { + return data; + } +} + + +contract C is A { + modifier mod1 override { + data |= 4; + _; + } +} + +// ---- +// getData() -> 6 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_library.sol b/test/libsolidity/semanticTests/extracted/function_modifier_library.sol new file mode 100644 index 000000000000..f10ebb0e74bb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_library.sol @@ -0,0 +1,28 @@ +library L { + struct S { + uint256 v; + } + modifier mod(S storage s) { + s.v++; + _; + } + + function libFun(S storage s) internal mod(s) { + s.v += 0x100; + } +} + + +contract Test { + using L for *; + L.S s; + + function f() public returns (uint256) { + s.libFun(); + L.libFun(s); + return s.v; + } +} + +// ---- +// f() -> 0x202 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol b/test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol new file mode 100644 index 000000000000..3d5e97de00f2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol @@ -0,0 +1,34 @@ +// Tests that virtual lookup for modifiers in libraries does not consider +// the current inheritance hierarchy. +library L { + struct S { + uint256 v; + } + modifier mod(S storage s) { + s.v++; + _; + } + + function libFun(S storage s) internal mod(s) { + s.v += 0x100; + } +} + + +contract Test { + using L for *; + L.S s; + modifier mod(L.S storage) { + revert(); + _; + } + + function f() public returns (uint256) { + s.libFun(); + L.libFun(s); + return s.v; + } +} + +// ---- +// f() -> 0x202 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol b/test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol new file mode 100644 index 000000000000..1df8b0874161 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol @@ -0,0 +1,19 @@ +contract C { + modifier mod1 { + uint8 a = 1; + uint8 b = 2; + _; + } + modifier mod2(bool a) { + if (a) return; + else _; + } + + function f(bool a) public mod1 mod2(a) returns (uint256 r) { + return 3; + } +} + +// ---- +// f(bool): true -> 0 +// f(bool): false -> 3 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_loop.sol b/test/libsolidity/semanticTests/extracted/function_modifier_loop.sol new file mode 100644 index 000000000000..0c4c07828af2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_loop.sol @@ -0,0 +1,13 @@ +contract C { + modifier repeat(uint256 count) { + uint256 i; + for (i = 0; i < count; ++i) _; + } + + function f() public repeat(10) returns (uint256 r) { + r += 1; + } +} + +// ---- +// f() -> 10 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol b/test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol new file mode 100644 index 000000000000..124e1597001e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol @@ -0,0 +1,14 @@ +contract C { + modifier repeat(bool twice) { + if (twice) _; + _; + } + + function f(bool twice) public repeat(twice) returns (uint256 r) { + r += 1; + } +} + +// ---- +// f(bool): false -> 1 +// f(bool): true -> 2 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol b/test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol new file mode 100644 index 000000000000..286476820029 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol @@ -0,0 +1,17 @@ +// Note that return sets the return variable and jumps to the end of the current function or +// modifier code block. +contract C { + modifier repeat(bool twice) { + if (twice) _; + _; + } + + function f(bool twice) public repeat(twice) returns (uint256 r) { + r += 1; + return r; + } +} + +// ---- +// f(bool): false -> 1 +// f(bool): true -> 2 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol b/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol new file mode 100644 index 000000000000..722334ec9250 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol @@ -0,0 +1,15 @@ +contract C { + uint256 public a; + modifier mod(uint256 x) { + a += x; + _; + } + + function f(uint256 x) public mod(2) mod(5) mod(x) returns (uint256) { + return a; + } +} + +// ---- +// f(uint256): 3 -> 10 +// a() -> 10 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol b/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol new file mode 100644 index 000000000000..64354ba5e250 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol @@ -0,0 +1,18 @@ +contract C { + uint256 public a; + modifier mod(uint256 x) { + uint256 b = x; + a += b; + _; + a -= b; + assert(b == x); + } + + function f(uint256 x) public mod(2) mod(5) mod(x) returns (uint256) { + return a; + } +} + +// ---- +// f(uint256): 3 -> 10 +// a() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol b/test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol new file mode 100644 index 000000000000..c91869615517 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol @@ -0,0 +1,19 @@ +contract A { + function f() public mod returns (bool r) { + return true; + } + + modifier mod virtual { + _; + } +} + + +contract C is A { + modifier mod override { + if (false) _; + } +} + +// ---- +// f() -> false diff --git a/test/libsolidity/semanticTests/extracted/function_type_library_internal.sol b/test/libsolidity/semanticTests/extracted/function_type_library_internal.sol new file mode 100644 index 000000000000..f096a4979444 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_type_library_internal.sol @@ -0,0 +1,26 @@ +library Utils { + function reduce( + uint256[] memory array, + function(uint, uint) internal returns (uint) f, + uint256 init + ) internal returns (uint256) { + for (uint256 i = 0; i < array.length; i++) { + init = f(array[i], init); + } + return init; + } + + function sum(uint256 a, uint256 b) internal returns (uint256) { + return a + b; + } +} + + +contract C { + function f(uint256[] memory x) public returns (uint256) { + return Utils.reduce(x, Utils.sum, 0); + } +} + +// ---- +// f(uint256[]): 0x20, 0x3, 0x1, 0x7, 0x3 -> 11 diff --git a/test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol new file mode 100644 index 000000000000..e92a37b19583 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol @@ -0,0 +1,24 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } + + function g() public returns (uint256 r) { + return 2; + } +} + + +contract Base is BaseBase(BaseBase.g()) {} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } +} + +// ---- +// getA() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol b/test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol new file mode 100644 index 000000000000..42db8582aed1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol @@ -0,0 +1,21 @@ +contract Test { + bytes3 name; + bool flag; + + constructor() public { + setName("abc"); + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function setName(bytes3 _name) private { + name = _name; + } +} + +// ==== +// compileViaYul: also +// ---- +// getName() -> "abc" diff --git a/test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol b/test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol new file mode 100644 index 000000000000..aaafb6f28293 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol @@ -0,0 +1,44 @@ +contract helper { + bool flag; + + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } + + function setFlag() public { + flag = true; + } + + function getFlag() public returns (bool fl) { + return flag; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public payable returns (uint256 bal) { + return h.getBalance.value(amount)(); + } + + function outOfGas() public returns (bool ret) { + h.setFlag.gas(2)(); // should fail due to OOG + return true; + } + + function checkState() public returns (bool flagAfter, uint256 myBal) { + flagAfter = h.getFlag(); + myBal = address(this).balance; + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 5 +// outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # +// checkState() -> false, 15 diff --git a/test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol new file mode 100644 index 000000000000..dbd524deb744 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol @@ -0,0 +1,43 @@ +contract helper { + bool flag; + + function getBalance() payable public returns(uint256 myBalance) { + return address(this).balance; + } + + function setFlag() public { + flag = true; + } + + function getFlag() public returns(bool fl) { + return flag; + } +} +contract test { + helper h; + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint amount) public payable returns(uint256 bal) { + return h.getBalance{value: amount}(); + } + + function outOfGas() public returns(bool ret) { + h.setFlag { + gas: 2 + }(); // should fail due to OOG + return true; + } + + function checkState() public returns(bool flagAfter, uint myBal) { + flagAfter = h.getFlag(); + myBal = address(this).balance; + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 5 +// outOfGas() -> FAILURE # call to helper should not succeed but amount should be transferred anyway # +// checkState() -> false, 15 \ No newline at end of file diff --git a/test/libsolidity/semanticTests/extracted/gasleft_decrease.sol b/test/libsolidity/semanticTests/extracted/gasleft_decrease.sol new file mode 100644 index 000000000000..8de56296e0b7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/gasleft_decrease.sol @@ -0,0 +1,20 @@ +contract C { + uint256 v; + + function f() public returns (bool) { + uint256 startGas = gasleft(); + v++; + assert(startGas > gasleft()); + return true; + } + + function g() public returns (bool) { + uint256 startGas = gasleft(); + assert(startGas > gasleft()); + return true; + } +} + +// ---- +// f() -> true +// g() -> true diff --git a/test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol b/test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol new file mode 100644 index 000000000000..00c0eabed3ba --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol @@ -0,0 +1,14 @@ +contract C { + function gasleft() public returns (uint256) { + return 0; + } + + function f() public returns (uint256) { + return gasleft(); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol new file mode 100644 index 000000000000..e25db0dcbbc1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol @@ -0,0 +1,13 @@ +contract A { + uint256 constant x = 7; +} + + +contract B is A { + function f() public returns (uint256) { + return A.x; + } +} + +// ---- +// f() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/inherited_function.sol b/test/libsolidity/semanticTests/extracted/inherited_function.sol new file mode 100644 index 000000000000..23f9bee371ac --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_function.sol @@ -0,0 +1,19 @@ +contract A { + function f() internal virtual returns (uint256) { + return 1; + } +} + + +contract B is A { + function f() internal override returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return A.f(); + } +} + +// ---- +// g() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol new file mode 100644 index 000000000000..9812ca5208d8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol @@ -0,0 +1,25 @@ +interface I { + function f(uint256[] calldata a) external returns (uint256); +} + + +contract A is I { + function f(uint256[] calldata a) external override returns (uint256) { + return 42; + } +} + + +contract B { + function f(uint256[] memory a) public returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + I i = I(new A()); + return i.f(new uint256[](2)); + } +} + +// ---- +// g() -> 42 diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol new file mode 100644 index 000000000000..0fd02e8f3a9f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol @@ -0,0 +1,22 @@ +contract A { + function f(uint256[] calldata a) external virtual returns (uint256) { + return a[0]; + } +} + + +contract B is A { + function f(uint256[] memory a) public override returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + uint256[] memory m = new uint256[](2); + m[0] = 42; + m[1] = 23; + return A(this).f(m); + } +} + +// ---- +// g() -> 23 diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol new file mode 100644 index 000000000000..9a2c1a1e7d07 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol @@ -0,0 +1,25 @@ +interface I { + function f(uint256[] calldata a) external returns (uint256); +} + + +contract A is I { + function f(uint256[] memory a) public override returns (uint256) { + return 42; + } +} + + +contract B { + function f(uint256[] memory a) public returns (uint256) { + return a[1]; + } + + function g() public returns (uint256) { + I i = I(new A()); + return i.f(new uint256[](2)); + } +} + +// ---- +// g() -> 42 diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol b/test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol new file mode 100644 index 000000000000..42d4f711c9b9 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol @@ -0,0 +1,19 @@ +library A { + function f() internal returns (uint256) { + return 1; + } +} + + +contract B { + function f() internal returns (uint256) { + return 2; + } + + function g() public returns (uint256) { + return A.f(); + } +} + +// ---- +// g() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol b/test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol new file mode 100644 index 000000000000..8dc5a7451b9f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (uint256) { + return ([1, 2, 3, 4][2]); + } +} + +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol b/test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol new file mode 100644 index 000000000000..19dfcf3b75e1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol @@ -0,0 +1,15 @@ +contract C { + string public tester; + + function f() public returns (string memory) { + return (["abc", "def", "g"][0]); + } + + function test() public { + tester = f(); + } +} + +// ---- +// test() -> +// tester() -> 0x20, 0x3, "abc" diff --git a/test/libsolidity/semanticTests/extracted/inline_array_return.sol b/test/libsolidity/semanticTests/extracted/inline_array_return.sol new file mode 100644 index 000000000000..e247d15586c8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_return.sol @@ -0,0 +1,15 @@ +contract C { + uint8[] tester; + + function f() public returns (uint8[5] memory) { + return ([1, 2, 3, 4, 5]); + } + + function test() public returns (uint8, uint8, uint8, uint8, uint8) { + tester = f(); + return (tester[0], tester[1], tester[2], tester[3], tester[4]); + } +} + +// ---- +// f() -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/extracted/inline_array_singleton.sol b/test/libsolidity/semanticTests/extracted/inline_array_singleton.sol new file mode 100644 index 000000000000..5925aba0f28e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_singleton.sol @@ -0,0 +1,9 @@ +// This caused a failure since the type was not converted to its mobile type. +contract C { + function f() public returns (uint256) { + return [4][0]; + } +} + +// ---- +// f() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol b/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol new file mode 100644 index 000000000000..f3f37ea20edb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint256 x, uint256 y) { + x = 3; + y = 6; + uint256[2] memory z = [x, y]; + return (z[0], z[1]); + } +} + +// ---- +// f() -> 3, 6 diff --git a/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol b/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol new file mode 100644 index 000000000000..fa9f24a7a856 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol @@ -0,0 +1,12 @@ +contract C { + string s = "doh"; + + function f() public returns (string memory, string memory) { + string memory t = "ray"; + string[3] memory x = [s, t, "mi"]; + return (x[1], x[2]); + } +} + +// ---- +// f() -> 0x40, 0x80, 0x3, "ray", 0x2, "mi" diff --git a/test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol b/test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol new file mode 100644 index 000000000000..ebcae638a105 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 i) public returns (string memory) { + string[4] memory x = ["This", "is", "an", "array"]; + return (x[i]); + } +} + +// ---- +// f(uint256): 0 -> 0x20, 0x4, "This" +// f(uint256): 1 -> 0x20, 0x2, "is" +// f(uint256): 2 -> 0x20, 0x2, "an" +// f(uint256): 3 -> 0x20, 0x5, "array" diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol new file mode 100644 index 000000000000..3d31c1addfa3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol @@ -0,0 +1,27 @@ +contract C { + function f() public { + assembly { + let d:= 0x10 + + function asmfun(a, b, c) - > x, y, z { + x := g(a) + function g(r) - > s { + s := mul(r, r) + } + y := g(b) + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + mstore(0x60, d) + return (0, 0x80) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1, 0x4, 0x7, 0x10 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_for.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_for.sol new file mode 100644 index 000000000000..451ecbbe50b8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_for.sol @@ -0,0 +1,26 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + function fac(n) -> nf { + nf := 1 + for { + let i := n + } gt(i, 0) { + i := sub(i, 1) + } { + nf := mul(nf, i) + } + } + b := fac(a) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 1 +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 6 +// f(uint256): 4 -> 24 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol new file mode 100644 index 000000000000..2c05f1556086 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol @@ -0,0 +1,29 @@ +contract C { + uint256 st; + + function f(uint256 a) public returns (uint256 b, uint256 c, uint256 d) { + st = 0; + assembly { + function sideeffect(r) -> x { + sstore(0, add(sload(0), r)) + x := 1 + } + for { + let i := a + } eq(i, sideeffect(2)) { + d := add(d, 3) + } { + b := i + i := 0 + } + } + c = st; + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 0, 2, 0 +// f(uint256): 1 -> 1, 4, 3 +// f(uint256): 2 -> 0, 2, 0 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol new file mode 100644 index 000000000000..17a271d5b333 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol @@ -0,0 +1,21 @@ +contract C { + function f() public { + assembly { + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + return (0, 0x60) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2, 7 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol new file mode 100644 index 000000000000..26d3d43b7def --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol @@ -0,0 +1,24 @@ +contract C { + function f() public { + assembly { + let d := 0x10 + + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + let a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + mstore(0x60, d) + return (0, 0x80) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0x1, 0x2, 0x7, 0x10 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol new file mode 100644 index 000000000000..2dec9761bbfb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol @@ -0,0 +1,23 @@ +contract C { + function f() public { + assembly { + let a1, b1, c1 + + function asmfun(a, b, c) - > x, y, z { + x := a + y := b + z := 7 + } + a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + return (0, 0x60) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 2, 7 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_if.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_if.sol new file mode 100644 index 000000000000..9f94f3c1991b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_if.sol @@ -0,0 +1,17 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + if gt(a, 1) { + b := 2 + } + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 0 +// f(uint256): 1 -> 0 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 2 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol new file mode 100644 index 000000000000..3c9f3a2f371f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol @@ -0,0 +1,19 @@ +contract C { + modifier m { + uint256 a = 1; + assembly { + a := 2 + } + if (a != 2) revert(); + _; + } + + function f() public m returns (bool) { + return true; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol new file mode 100644 index 000000000000..b43b5f611a02 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol @@ -0,0 +1,13 @@ +contract C { + function test() public returns (bytes memory) { + bytes memory x = new bytes(5); + for (uint256 i = 0; i < x.length; ++i) x[i] = bytes1(uint8(i + 1)); + assembly { + mstore(add(x, 32), "12345678901234567890123456789012") + } + return x; + } +} + +// ---- +// test() -> 0x20, 0x5, "12345" diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol new file mode 100644 index 000000000000..c48d749676cb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol @@ -0,0 +1,13 @@ +contract C { + function f() public returns (uint256 r) { + for (uint256 x = 0; x < 10; ++x) + assembly { + r := add(r, x) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 45 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol new file mode 100644 index 000000000000..a5e3c4675661 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol @@ -0,0 +1,28 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + function fac(n) -> nf { + switch n + case 0 { + nf := 1 + } + case 1 { + nf := 1 + } + default { + nf := mul(n, fac(sub(n, 1))) + } + } + b := fac(a) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 1 +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 3 -> 6 +// f(uint256): 4 -> 24 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol new file mode 100644 index 000000000000..823afe2bdac6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol @@ -0,0 +1,22 @@ +contract C { + uint16 x; + uint16 public y; + uint256 public z; + + function f() public returns (bool) { + uint256 off1; + uint256 off2; + assembly { + sstore(z_slot, 7) + off1 := z_offset + off2 := y_offset + } + assert(off1 == 0); + assert(off2 == 2); + return true; + } +} + +// ---- +// f() -> true +// z() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol new file mode 100644 index 000000000000..ce56dbaa1965 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol @@ -0,0 +1,23 @@ +contract C { + uint16 x; + uint16 public y; + uint256 public z; + + function f() public returns (bool) { + uint256 off1; + uint256 off2; + assembly { + function f() -> o1 { + sstore(z_slot, 7) + o1 := y_offset + } + off2 := f() + } + assert(off2 == 2); + return true; + } +} + +// ---- +// f() -> true +// z() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol new file mode 100644 index 000000000000..3893c8e89b2f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol @@ -0,0 +1,25 @@ +contract C { + struct Data { + uint256 contents; + } + uint256 public separator; + Data public a; + uint256 public separator2; + + function f() public returns (bool) { + Data storage x = a; + uint256 off; + assembly { + sstore(x_slot, 7) + off := x_offset + } + assert(off == 0); + return true; + } +} + +// ---- +// f() -> true +// a() -> 7 +// separator() -> 0 +// separator2() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol new file mode 100644 index 000000000000..9b9a76109c7a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol @@ -0,0 +1,24 @@ +contract C { + function f(uint256 a) public returns (uint256 b) { + assembly { + switch a + case 1 { + b := 8 + } + case 2 { + b := 9 + } + default { + b := 2 + } + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0 -> 2 +// f(uint256): 1 -> 8 +// f(uint256): 2 -> 9 +// f(uint256): 3 -> 2 diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol b/test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol new file mode 100644 index 000000000000..fa981fbd3352 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol @@ -0,0 +1,13 @@ +contract C { + function f() public returns (uint256 r, bytes32 r2) { + assembly { + r := 7 + r2 := "abcdef" + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 7, "abcdef" diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init.sol b/test/libsolidity/semanticTests/extracted/inline_member_init.sol new file mode 100644 index 000000000000..5dca66d80c07 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_member_init.sol @@ -0,0 +1,19 @@ +contract test { + constructor() public { + m_b = 6; + m_c = 8; + } + + uint256 m_a = 5; + uint256 m_b; + uint256 m_c = 7; + + function get() public returns (uint256 a, uint256 b, uint256 c) { + a = m_a; + b = m_b; + c = m_c; + } +} + +// ---- +// get() -> 5, 6, 8 diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol b/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol new file mode 100644 index 000000000000..53f5b3718be7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol @@ -0,0 +1,24 @@ +contract Base { + constructor() public {} + + uint256 m_base = 5; + + function getBMember() public returns (uint256 i) { + return m_base; + } +} + + +contract Derived is Base { + constructor() public {} + + uint256 m_derived = 6; + + function getDMember() public returns (uint256 i) { + return m_derived; + } +} + +// ---- +// getBMember() -> 5 +// getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol b/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol new file mode 100644 index 000000000000..0aea44e6a493 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol @@ -0,0 +1,20 @@ +contract Base { + uint256 m_base = 5; + + function getBMember() public returns (uint256 i) { + return m_base; + } +} + + +contract Derived is Base { + uint256 m_derived = 6; + + function getDMember() public returns (uint256 i) { + return m_derived; + } +} + +// ---- +// getBMember() -> 5 +// getDMember() -> 6 diff --git a/test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol b/test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol new file mode 100644 index 000000000000..e350a11d3f51 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol @@ -0,0 +1,9 @@ +contract c { + function f() public returns (int8) { + int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; + return foo3[0]; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol b/test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol new file mode 100644 index 000000000000..250e0ce8a0c6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol @@ -0,0 +1,15 @@ +contract C { + function f() public pure returns (uint a, uint b) { + assembly { + let x + let y, z + a := x + b := z + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0, 0 diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function.sol b/test/libsolidity/semanticTests/extracted/internal_library_function.sol new file mode 100644 index 000000000000..a3c8a870018e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/internal_library_function.sol @@ -0,0 +1,21 @@ +// tests that internal library functions can be called from outside +// and retain the same memory context (i.e. are pulled into the caller's code) +// This has to work without linking, because everything will be inlined. +library L { + function f(uint256[] memory _data) internal { + _data[3] = 2; + } +} + + +contract C { + function f() public returns (uint256) { + uint256[] memory x = new uint256[](7); + x[3] = 8; + L.f(x); + return x[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol b/test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol new file mode 100644 index 000000000000..f59ec9440dff --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol @@ -0,0 +1,26 @@ +// This has to work without linking, because everything will be inlined. +library L { + struct S { + uint256[] data; + } + + function f(S memory _s) internal { + _s.data[3] = 2; + } +} + + +contract C { + using L for L.S; + + function f() public returns (uint256) { + L.S memory x; + x.data = new uint256[](7); + x.data[3] = 8; + x.f(); + return x.data[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol b/test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol new file mode 100644 index 000000000000..2283c30ff5fc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol @@ -0,0 +1,26 @@ +// tests that internal library functions that are called from outside and that +// themselves call private functions are still able to (i.e. the private function +// also has to be pulled into the caller's code) +// This has to work without linking, because everything will be inlined. +library L { + function g(uint256[] memory _data) private { + _data[3] = 2; + } + + function f(uint256[] memory _data) internal { + g(_data); + } +} + + +contract C { + function f() public returns (uint256) { + uint256[] memory x = new uint256[](7); + x[3] = 8; + L.f(x); + return x[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol b/test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol new file mode 100644 index 000000000000..21417b599b43 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol @@ -0,0 +1,26 @@ +// This has to work without linking, because everything will be inlined. +library L { + struct S { + uint256[] data; + } + + function f(S memory _s) internal returns (uint256[] memory) { + _s.data[3] = 2; + return _s.data; + } +} + + +contract C { + using L for L.S; + + function f() public returns (uint256) { + L.S memory x; + x.data = new uint256[](7); + x.data[3] = 8; + return x.f()[3]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol b/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol new file mode 100644 index 000000000000..d0adf2785d41 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol @@ -0,0 +1,20 @@ +contract C { + enum X {A, B} + + function tested(X x) public returns (uint256) { + return 1; + } + + function test() public returns (uint256) { + X garbled; + + assembly { + garbled := 5 + } + + return this.tested(garbled); + } +} + +// ---- +// test() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol b/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol new file mode 100644 index 000000000000..6bdf14298809 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol @@ -0,0 +1,32 @@ +contract C { + enum X {A, B} + + function test_return() public returns (X) { + X garbled; + assembly { + garbled := 5 + } + return garbled; + } + + function test_inline_assignment() public returns (X _ret) { + assembly { + _ret := 5 + } + } + + function test_assignment() public returns (X _ret) { + X tmp; + assembly { + tmp := 5 + } + _ret = tmp; + } +} + +// ==== +// compileViaYul: also +// ---- +// test_return() -> FAILURE # both should throw # +// test_inline_assignment() -> FAILURE +// test_assignment() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol b/test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol new file mode 100644 index 000000000000..17ee32bb889e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol @@ -0,0 +1,29 @@ +contract C { + enum X {A, B} + + function test_eq() public returns (bool) { + X garbled; + assembly { + garbled := 5 + } + return garbled == garbled; + } + + function test_eq_ok() public returns (bool) { + X garbled = X.A; + return garbled == garbled; + } + + function test_neq() public returns (bool) { + X garbled; + assembly { + garbled := 5 + } + return garbled != garbled; + } +} + +// ---- +// test_eq_ok() -> 1 +// test_eq() -> FAILURE # both should throw # +// test_neq() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol b/test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol new file mode 100644 index 000000000000..2b90451ec639 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol @@ -0,0 +1,23 @@ +contract C { + enum X {A, B} + X public x; + + function test_store() public returns (uint256) { + X garbled = X.A; + assembly { + garbled := 5 + } + x = garbled; + return 1; + } + + function test_store_ok() public returns (uint256) { + x = X.A; + return 1; + } +} + +// ---- +// test_store_ok() -> 1 +// x() -> 0 +// test_store() -> FAILURE # should throw # diff --git a/test/libsolidity/semanticTests/extracted/invalid_instruction.sol b/test/libsolidity/semanticTests/extracted/invalid_instruction.sol new file mode 100644 index 000000000000..839296ca193a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/invalid_instruction.sol @@ -0,0 +1,12 @@ +contract C { + function f() public { + assembly { + invalid() + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol b/test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol new file mode 100644 index 000000000000..743825d607f4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol @@ -0,0 +1,19 @@ +// A long time ago, some opcodes were renamed, which involved the opcodes +// "iszero" and "not". +contract C { + function f() public returns (bool) { + bytes32 x = bytes32(uint256(1)); + assembly { + x := not(x) + } + if (x != ~bytes32(uint256(1))) return false; + assembly { + x := iszero(x) + } + if (x != bytes32(0)) return false; + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/keccak256_assembly.sol b/test/libsolidity/semanticTests/extracted/keccak256_assembly.sol new file mode 100644 index 000000000000..d4034f10bee5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_assembly.sol @@ -0,0 +1,12 @@ +contract C { + function f() public pure returns (bytes32 ret) { + assembly { + ret := keccak256(0, 0) + } + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 diff --git a/test/libsolidity/semanticTests/extracted/keccak256_empty.sol b/test/libsolidity/semanticTests/extracted/keccak256_empty.sol new file mode 100644 index 000000000000..1374538c2c04 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_empty.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (bytes32) { + return keccak256(""); + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 diff --git a/test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol b/test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol new file mode 100644 index 000000000000..725d984d86f8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol @@ -0,0 +1,13 @@ +contract c { + bytes data; + + function foo() public returns (bool) { + data.push("f"); + data.push("o"); + data.push("o"); + return keccak256(data) == keccak256("foo"); + } +} + +// ---- +// foo() -> true diff --git a/test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol b/test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol new file mode 100644 index 000000000000..f24d93c2d940 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol @@ -0,0 +1,14 @@ +library Arst { + enum Foo {Things, Stuff} +} + + +contract Tsra { + function f() public returns (uint256) { + Arst.Foo; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol b/test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol new file mode 100644 index 000000000000..d7df52434136 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol @@ -0,0 +1,17 @@ +library Arst { + struct Foo { + int256 Things; + int256 Stuff; + } +} + + +contract Tsra { + function f() public returns (uint256) { + Arst.Foo; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/literal_empty_string.sol b/test/libsolidity/semanticTests/extracted/literal_empty_string.sol new file mode 100644 index 000000000000..bf4da54099af --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/literal_empty_string.sol @@ -0,0 +1,20 @@ +contract C { + bytes32 public x; + uint256 public a; + + function f(bytes32 _x, uint256 _a) public { + x = _x; + a = _a; + } + + function g() public { + this.f("", 2); + } +} + +// ---- +// x() -> 0 +// a() -> 0 +// g() -> +// x() -> 0 +// a() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol b/test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol new file mode 100644 index 000000000000..829345d2e9f9 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol @@ -0,0 +1,16 @@ +contract C { + struct s { + uint256 a; + uint256 b; + } + + function f() public returns (uint256) { + s[7][]; // This is only the type, should not have any effect + return 3; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/mapping_of_functions.sol b/test/libsolidity/semanticTests/extracted/mapping_of_functions.sol new file mode 100644 index 000000000000..ac802ee9e5da --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/mapping_of_functions.sol @@ -0,0 +1,34 @@ +contract Flow { + bool public success; + + mapping(address => function() internal) stages; + + function stage0() internal { + stages[msg.sender] = stage1; + } + + function stage1() internal { + stages[msg.sender] = stage2; + } + + function stage2() internal { + success = true; + } + + constructor() public { + stages[msg.sender] = stage0; + } + + function f() public returns (uint256) { + stages[msg.sender](); + return 7; + } +} + +// ---- +// success() -> false +// f() -> 7 +// f() -> 7 +// success() -> false +// f() -> 7 +// success() -> true diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol b/test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol new file mode 100644 index 000000000000..b641ec1daa9c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol @@ -0,0 +1,17 @@ +// Computes binomial coefficients the chinese way +contract C { + function f(uint256 n, uint256 k) public returns (uint256) { + uint256[][] memory rows = new uint256[][](n + 1); + for (uint256 i = 1; i <= n; i++) { + rows[i] = new uint256[](i); + rows[i][0] = rows[i][rows[i].length - 1] = 1; + for (uint256 j = 1; j < i - 1; j++) + rows[i][j] = rows[i - 1][j - 1] + rows[i - 1][j]; + } + return rows[n][k - 1]; + } +} + +// ---- +// f(uint256,uint256): 3, 1 -> 1 +// f(uint256,uint256): 9, 5 -> 70 diff --git a/test/libsolidity/semanticTests/extracted/memory_overwrite.sol b/test/libsolidity/semanticTests/extracted/memory_overwrite.sol new file mode 100644 index 000000000000..7312509e2ff0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_overwrite.sol @@ -0,0 +1,10 @@ +contract C { + function f() public returns (bytes memory x) { + x = "12345"; + x[3] = 0x61; + x[0] = 0x62; + } +} + +// ---- +// f() -> 0x20, 5, "b23a5" diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol b/test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol new file mode 100644 index 000000000000..1173a3796590 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol @@ -0,0 +1,32 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + } + + function test() public returns (uint256 x, uint256 y, uint256 z) { + S memory data = combine(1, 2, 3); + x = extract(data, 0); + y = extract(data, 1); + z = extract(data, 2); + } + + function extract(S memory s, uint256 which) internal returns (uint256 x) { + if (which == 0) return s.x; + else if (which == 1) return s.y; + else return s.z; + } + + function combine(uint8 x, uint16 y, uint256 z) + internal + returns (S memory s) + { + s.x = x; + s.y = y; + s.z = z; + } +} + +// ---- +// test() -> 1, 2, 3 diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_nested.sol b/test/libsolidity/semanticTests/extracted/memory_structs_nested.sol new file mode 100644 index 000000000000..f5c41a232b09 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_structs_nested.sol @@ -0,0 +1,42 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + } + struct X { + uint8 x; + S s; + } + + function test() + public + returns (uint256 a, uint256 x, uint256 y, uint256 z) + { + X memory d = combine(1, 2, 3, 4); + a = extract(d, 0); + x = extract(d, 1); + y = extract(d, 2); + z = extract(d, 3); + } + + function extract(X memory s, uint256 which) internal returns (uint256 x) { + if (which == 0) return s.x; + else if (which == 1) return s.s.x; + else if (which == 2) return s.s.y; + else return s.s.z; + } + + function combine(uint8 a, uint8 x, uint16 y, uint256 z) + internal + returns (X memory s) + { + s.x = a; + s.s.x = x; + s.s.y = y; + s.s.z = z; + } +} + +// ---- +// test() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol b/test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol new file mode 100644 index 000000000000..105f599099fb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol @@ -0,0 +1,56 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + uint8[2] a; + } + S[5] data; + + function testInit() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a, bool flag) + { + S[2] memory d; + x = d[0].x; + y = d[0].y; + z = d[0].z; + a = d[0].a[1]; + flag = true; + } + + function testCopyRead() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a) + { + data[2].x = 1; + data[2].y = 2; + data[2].z = 3; + data[2].a[1] = 4; + S memory s = data[2]; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } + + function testAssign() + public + returns (uint8 x, uint16 y, uint256 z, uint8 a) + { + S memory s; + s.x = 1; + s.y = 2; + s.z = 3; + s.a[1] = 4; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } +} + +// ---- +// testInit() -> 0, 0, 0, 0, true +// testCopyRead() -> 1, 2, 3, 4 +// testAssign() -> 1, 2, 3, 4 diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol b/test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol new file mode 100644 index 000000000000..3aaa354f88f1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol @@ -0,0 +1,24 @@ +contract Test { + struct S { + uint8 a; + mapping(uint256 => uint256) b; + uint8 c; + } + S s; + + function f() public returns (uint256) { + S memory x; + if (x.a != 0 || x.c != 0) return 1; + x.a = 4; + x.c = 5; + s = x; + if (s.a != 4 || s.c != 5) return 2; + x = S(2, 3); + if (x.a != 2 || x.c != 3) return 3; + x = s; + if (s.a != 4 || s.c != 5) return 4; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol b/test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol new file mode 100644 index 000000000000..6f79442e7aff --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol @@ -0,0 +1,47 @@ +contract C { + function g() public returns (uint256 a, uint256 b, uint256 c) { + a = 1; + b = 2; + c = 3; + } + + function h() public returns (uint256 a, uint256 b, uint256 c, uint256 d) { + a = 1; + b = 2; + c = 3; + d = 4; + } + + function f1() public returns (bool) { + (uint256 x, uint256 y, uint256 z) = g(); + if (x != 1 || y != 2 || z != 3) return false; + (, uint256 a, ) = g(); + if (a != 2) return false; + (uint256 b, , ) = g(); + if (b != 1) return false; + (, , uint256 c) = g(); + if (c != 3) return false; + return true; + } + + function f2() public returns (bool) { + (uint256 a1, , uint256 a3, ) = h(); + if (a1 != 1 || a3 != 3) return false; + (uint256 b1, uint256 b2, , ) = h(); + if (b1 != 1 || b2 != 2) return false; + (, uint256 c2, uint256 c3, ) = h(); + if (c2 != 2 || c3 != 3) return false; + (, , uint256 d3, uint256 d4) = h(); + if (d3 != 3 || d4 != 4) return false; + (uint256 e1, , uint256 e3, uint256 e4) = h(); + if (e1 != 1 || e3 != 3 || e4 != 4) return false; + return true; + } + + function f() public returns (bool) { + return f1() && f2(); + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/negative_stack_height.sol b/test/libsolidity/semanticTests/extracted/negative_stack_height.sol new file mode 100644 index 000000000000..d5074dc911fc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/negative_stack_height.sol @@ -0,0 +1,63 @@ +contract C { + mapping(uint256 => Invoice) public invoices; + struct Invoice { + uint256 AID; + bool Aboola; + bool Aboolc; + bool exists; + } + + function nredit(uint256 startindex) + public + pure + returns ( + uint256[500] memory CIDs, + uint256[500] memory dates, + uint256[500] memory RIDs, + bool[500] memory Cboolas, + uint256[500] memory amounts + ) + {} + + function return500InvoicesByDates( + uint256 begindate, + uint256 enddate, + uint256 startindex + ) + public + view + returns ( + uint256[500] memory AIDs, + bool[500] memory Aboolas, + uint256[500] memory dates, + bytes32[3][500] memory Abytesas, + bytes32[3][500] memory bytesbs, + bytes32[2][500] memory bytescs, + uint256[500] memory amounts, + bool[500] memory Aboolbs, + bool[500] memory Aboolcs + ) + {} + + function return500PaymentsByDates( + uint256 begindate, + uint256 enddate, + uint256 startindex + ) + public + view + returns ( + uint256[500] memory BIDs, + uint256[500] memory dates, + uint256[500] memory RIDs, + bool[500] memory Bboolas, + bytes32[3][500] memory bytesbs, + bytes32[2][500] memory bytescs, + uint256[500] memory amounts, + bool[500] memory Bboolbs + ) + {} +} + +// ---- +// constructor() -> diff --git a/test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol b/test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol new file mode 100644 index 000000000000..f02fda353d50 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + uint256 b; + S1 s; + uint256 c; + } + + function f(S2 calldata s) + external + pure + returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) + { + return (s.a, s.b, s.s.a, s.s.b, s.c); + } +} + +// ---- +// f((uint256,uint256,(uint256,uint256),uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol new file mode 100644 index 000000000000..e0a25a857a8c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol @@ -0,0 +1,27 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S1 { + uint256 a; + uint256 b; + } + struct S2 { + uint256 a; + uint256 b; + S1 s; + uint256 c; + } + + function f(S2 calldata s) + external + pure + returns (uint256 a, uint256 b, uint256 sa, uint256 sb, uint256 c) + { + S2 memory m = s; + return (m.a, m.b, m.s.a, m.s.b, m.c); + } +} + +// ---- +// f((uint256,uint256,(uint256,uint256),uint256)): 1, 2, 3, 4, 5 -> 1, 2, 3, 4, 5 diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol b/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol new file mode 100644 index 000000000000..7f65eb4adb7d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol @@ -0,0 +1,18 @@ +contract test { + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function g() public returns (uint256 d) { + return f(3); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 3 diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol b/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol new file mode 100644 index 000000000000..bee0e8fa5723 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol @@ -0,0 +1,18 @@ +contract test { + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function g() public returns (uint256 d) { + return f(3, 7); + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 10 diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol b/test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol new file mode 100644 index 000000000000..df437a32c8ce --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol @@ -0,0 +1,20 @@ +contract test { + function f(uint256 a, uint256 b) public returns (uint256 d) { + return a + b; + } + + function f(uint256 k) public returns (uint256 d) { + return k; + } + + function g(bool flag) public returns (uint256 d) { + if (flag) return f(3); + else return f(3, 7); + } +} + +// ==== +// compileViaYul: also +// ---- +// g(bool): true -> 3 +// g(bool): false -> 10 diff --git a/test/libsolidity/semanticTests/extracted/packed_functions.sol b/test/libsolidity/semanticTests/extracted/packed_functions.sol new file mode 100644 index 000000000000..4a49a614f3b5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_functions.sol @@ -0,0 +1,48 @@ +contract C { + // these should take the same slot + function() internal returns (uint) a; + function() external returns (uint) b; + function() external returns (uint) c; + function() internal returns (uint) d; + uint8 public x; + + function set() public { + x = 2; + d = g; + c = this.h; + b = this.h; + a = g; + } + + function t1() public returns (uint256) { + return a(); + } + + function t2() public returns (uint256) { + return b(); + } + + function t3() public returns (uint256) { + return a(); + } + + function t4() public returns (uint256) { + return b(); + } + + function g() public returns (uint256) { + return 7; + } + + function h() public returns (uint256) { + return 8; + } +} + +// ---- +// set() -> +// t1() -> 7 +// t2() -> 8 +// t3() -> 7 +// t4() -> 8 +// x() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol b/test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol new file mode 100644 index 000000000000..9b20dbfd2c55 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol @@ -0,0 +1,16 @@ +contract C { + uint16 x = 0x1234; + uint16 a = 0xffff; + uint16 b; + + function f() public returns (uint256, uint256, uint256, uint256) { + a++; + uint256 c = b; + delete b; + a -= 2; + return (x, c, b, a); + } +} + +// ---- +// f() -> 0x1234, 0x0, 0x0, 0xfffe diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_signed.sol b/test/libsolidity/semanticTests/extracted/packed_storage_signed.sol new file mode 100644 index 000000000000..8db0c757ed3b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_storage_signed.sol @@ -0,0 +1,22 @@ +contract C { + int8 a; + uint8 b; + int8 c; + uint8 d; + + function test() + public + returns (uint256 x1, uint256 x2, uint256 x3, uint256 x4) + { + a = -2; + b = -uint8(a) * 2; + c = a * int8(120) * int8(121); + x1 = uint256(a); + x2 = b; + x3 = uint256(c); + x4 = d; + } +} + +// ---- +// test() -> -2, 4, -112, 0 diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol b/test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol new file mode 100644 index 000000000000..daeee6ba6f4d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol @@ -0,0 +1,45 @@ +contract C { + struct s1 { + bytes1 a; + bytes1 b; + bytes10 c; + bytes9 d; + bytes10 e; + } + struct s2 { + bytes1 a; + s1 inner; + bytes1 b; + bytes1 c; + } + bytes1 x; + s2 data; + bytes1 y; + + function test() public returns (bool) { + x = 0x01; + data.a = 0x02; + data.inner.a = 0x03; + data.inner.b = 0x04; + data.inner.c = "1234567890"; + data.inner.d = "123456789"; + data.inner.e = "abcdefghij"; + data.b = 0x05; + data.c = bytes1(0x06); + y = 0x07; + return + x == 0x01 && + data.a == 0x02 && + data.inner.a == 0x03 && + data.inner.b == 0x04 && + data.inner.c == "1234567890" && + data.inner.d == "123456789" && + data.inner.e == "abcdefghij" && + data.b == 0x05 && + data.c == bytes1(0x06) && + y == 0x07; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol b/test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol new file mode 100644 index 000000000000..9c9f778f0f85 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol @@ -0,0 +1,33 @@ +contract C { + enum small {A, B, C, D} + enum larger {A, B, C, D, E} + struct str { + small a; + small b; + larger c; + larger d; + } + str data; + + function test() public returns (uint256) { + data.a = small.B; + if (data.a != small.B) return 2; + data.b = small.C; + if (data.b != small.C) return 3; + data.c = larger.D; + if (data.c != larger.D) return 4; + if (data.a != small.B) return 5; + data.a = small.C; + if (data.a != small.C) return 6; + if (data.b != small.C) return 7; + data.b = small.D; + if (data.b != small.D) return 8; + if (data.c != larger.D) return 9; + data.c = larger.B; + if (data.c != larger.B) return 10; + return 1; + } +} + +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol b/test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol new file mode 100644 index 000000000000..8c91576f5003 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol @@ -0,0 +1,30 @@ +contract C { + struct str { + uint8 a; + uint16 b; + uint248 c; + } + str data; + + function test() public returns (uint256) { + data.a = 2; + if (data.a != 2) return 2; + data.b = 0xabcd; + if (data.b != 0xabcd) return 3; + data.c = 0x1234567890; + if (data.c != 0x1234567890) return 4; + if (data.a != 2) return 5; + data.a = 8; + if (data.a != 8) return 6; + if (data.b != 0xabcd) return 7; + data.b = 0xdcab; + if (data.b != 0xdcab) return 8; + if (data.c != 0x1234567890) return 9; + data.c = 0x9876543210; + if (data.c != 0x9876543210) return 10; + return 1; + } +} + +// ---- +// test() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol new file mode 100644 index 000000000000..26de9ce7087a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol @@ -0,0 +1,18 @@ +contract Base { + constructor(uint256 i) public { + m_i = i; + } + + uint256 public m_i; +} + + +contract Derived is Base { + constructor(uint256 i) public Base(i) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol new file mode 100644 index 000000000000..6349bd814ffd --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol @@ -0,0 +1,23 @@ +contract Base { + constructor(uint256 j) public { + m_i = j; + } + + uint256 public m_i; +} + + +contract Base1 is Base { + constructor(uint256 k) public Base(k) {} +} + + +contract Derived is Base, Base1 { + constructor(uint256 i) public Base1(i) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol new file mode 100644 index 000000000000..4556cf5c49eb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol @@ -0,0 +1,23 @@ +contract Base { + constructor(uint256 i) public { + m_i = i; + } + + uint256 public m_i; +} + + +abstract contract Base1 is Base { + constructor(uint256 k) public {} +} + + +contract Derived is Base, Base1 { + constructor(uint256 i) public Base(i) Base1(7) {} +} + + +contract Final is Derived(4) {} + +// ---- +// m_i() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol b/test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol new file mode 100644 index 000000000000..ebef9a2549a8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol @@ -0,0 +1,21 @@ +contract C { + function f(uint256 x) public returns (uint256) { + return this.eval(this.g, x); + } + + function f2(uint256 x) public returns (uint256) { + return eval(this.g, x); + } + + function eval(function(uint) external returns (uint) x, uint a) public returns (uint) { + return x(a); + } + + function g(uint256 x) public returns (uint256) { + return x + 1; + } +} + +// ---- +// f(uint256): 7 -> 8 +// f2(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol b/test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol new file mode 100644 index 000000000000..6fb4f5f6e439 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint256 x) public returns (uint256) { + return eval(g, x); + } + + function eval(function(uint) internal returns (uint) x, uint a) internal returns (uint) { + return x(a); + } + + function g(uint256 x) public returns (uint256) { + return x + 1; + } +} + +// ---- +// f(uint256): 7 -> 8 diff --git a/test/libsolidity/semanticTests/extracted/payable_constructor.sol b/test/libsolidity/semanticTests/extracted/payable_constructor.sol new file mode 100644 index 000000000000..9a3c56ebee66 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/payable_constructor.sol @@ -0,0 +1,8 @@ +contract C { + constructor() public payable {} +} + +// ==== +// compileViaYul: also +// ---- +// constructor(), 27 wei -> diff --git a/test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol b/test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol new file mode 100644 index 000000000000..9ba67b198b15 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol @@ -0,0 +1,10 @@ +contract test { + int8 public x = 2; + int8 public y = 127; + int16 public q = 250; +} + +// ---- +// x() -> 2 +// y() -> 127 +// q() -> 250 diff --git a/test/libsolidity/semanticTests/extracted/recursive_structs.sol b/test/libsolidity/semanticTests/extracted/recursive_structs.sol new file mode 100644 index 000000000000..da568a25548d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/recursive_structs.sol @@ -0,0 +1,19 @@ +contract C { + struct S { + S[] x; + } + S sstorage; + + function f() public returns (uint256) { + S memory s; + s.x = new S[](10); + delete s; + // TODO Uncomment after implemented. + // sstorage.x.push(); + delete sstorage; + return 1; + } +} + +// ---- +// f() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol b/test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol new file mode 100644 index 000000000000..c437922e4e2d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol @@ -0,0 +1,16 @@ +contract C { + uint256 public x; + modifier setsx { + _; + x = 9; + } + + function f() public setsx returns (uint256) { + return 2; + } +} + +// ---- +// x() -> 0 +// f() -> 2 +// x() -> 9 diff --git a/test/libsolidity/semanticTests/extracted/return_in_modifier.sol b/test/libsolidity/semanticTests/extracted/return_in_modifier.sol new file mode 100644 index 000000000000..81fbd794e3e4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/return_in_modifier.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 1; i < 10; i++) { + if (i == 5) return; + _; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/revert.sol b/test/libsolidity/semanticTests/extracted/revert.sol new file mode 100644 index 000000000000..eae49c799bc6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/revert.sol @@ -0,0 +1,21 @@ +contract C { + uint256 public a = 42; + + function f() public { + a = 1; + revert(); + } + + function g() public { + a = 1; + assembly { + revert(0, 0) + } + } +} + +// ---- +// f() -> FAILURE +// a() -> 42 +// g() -> FAILURE +// a() -> 42 diff --git a/test/libsolidity/semanticTests/extracted/ripemd160_empty.sol b/test/libsolidity/semanticTests/extracted/ripemd160_empty.sol new file mode 100644 index 000000000000..c79625d3cc5b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/ripemd160_empty.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (bytes20) { + return ripemd160(""); + } +} + +// ---- +// f() -> 0x9c1185a5c5e9fc54612808977ee8f548b2258d31000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol b/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol new file mode 100644 index 000000000000..a79cb2d76ff3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol @@ -0,0 +1,19 @@ +contract C { + uint256 public initial; + + constructor() public { + initial = double(2); + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } + + function runtime(uint256 _arg) public returns (uint256) { + return double(_arg); + } +} + +// ---- +// runtime(uint256): 3 -> 6 +// initial() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol b/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol new file mode 100644 index 000000000000..f8230b21aff4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol @@ -0,0 +1,18 @@ +contract C { + function(uint256) returns (uint256) internal x; + + constructor() public { + x = double; + } + + function test() public returns (bool) { + return x == double; + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/extracted/scientific_notation.sol b/test/libsolidity/semanticTests/extracted/scientific_notation.sol new file mode 100644 index 000000000000..e79fca70b80c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/scientific_notation.sol @@ -0,0 +1,36 @@ +contract C { + function f() public returns(uint) { + return 2e10 wei; + } + + function g() public returns(uint) { + return 200e-2 wei; + } + + function h() public returns(uint) { + return 2.5e1; + } + + function i() public returns(int) { + return -2e10; + } + + function j() public returns(int) { + return -200e-2; + } + + function k() public returns(int) { + return -2.5e1; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> 20000000000 +// g() -> 2 +// h() -> 25 +// i() -> -20000000000 +// j() -> -2 +// k() -> -25 + diff --git a/test/libsolidity/semanticTests/extracted/send_zero_ether.sol b/test/libsolidity/semanticTests/extracted/send_zero_ether.sol new file mode 100644 index 000000000000..e0c6ff5e03aa --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/send_zero_ether.sol @@ -0,0 +1,19 @@ +// Sending zero ether to a contract should still invoke the receive ether function +// (it previously did not because the gas stipend was not provided by the EVM) +contract Receiver { + receive() external payable {} +} + + +contract Main { + constructor() public payable {} + + function s() public returns (bool) { + Receiver r = new Receiver(); + return address(r).send(0); + } +} + +// ---- +// constructor(), 20 wei -> +// s() -> true diff --git a/test/libsolidity/semanticTests/extracted/senders_balance.sol b/test/libsolidity/semanticTests/extracted/senders_balance.sol new file mode 100644 index 000000000000..0c84352b6237 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/senders_balance.sol @@ -0,0 +1,20 @@ +contract C { + function f() public view returns (uint256) { + return msg.sender.balance; + } +} + + +contract D { + C c = new C(); + + constructor() public payable {} + + function f() public view returns (uint256) { + return c.f(); + } +} + +// ---- +// constructor(), 27 wei -> +// f() -> 27 diff --git a/test/libsolidity/semanticTests/extracted/sha256_empty.sol b/test/libsolidity/semanticTests/extracted/sha256_empty.sol new file mode 100644 index 000000000000..69b9e15f535c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/sha256_empty.sol @@ -0,0 +1,8 @@ +contract C { + function f() public returns (bytes32) { + return sha256(""); + } +} + +// ---- +// f() -> 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/test/libsolidity/semanticTests/extracted/shift_cleanup.sol b/test/libsolidity/semanticTests/extracted/shift_cleanup.sol new file mode 100644 index 000000000000..81296ba9520f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_cleanup.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint16 x) { + x = 0xffff; + x += 32; + x <<= 8; + x >>= 16; + } +} + +// ---- +// f() -> 0x0 diff --git a/test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol new file mode 100644 index 000000000000..cc81c15e4df3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol @@ -0,0 +1,11 @@ +contract C { + function f() public returns (uint8 x) { + assembly { + x := 0xffff + } + x >>= 8; + } +} + +// ---- +// f() -> 0x0 diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_left.sol b/test/libsolidity/semanticTests/extracted/shift_constant_left.sol new file mode 100644 index 000000000000..4c6f3737f654 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_constant_left.sol @@ -0,0 +1,6 @@ +contract C { + uint256 public a = 0x42 << 8; +} + +// ---- +// a() -> 0x4200 diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol new file mode 100644 index 000000000000..e5a4152b57b1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256 a) { + a = 0x42; + a <<= 8; + } +} + +// ---- +// f() -> 0x4200 diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_right.sol b/test/libsolidity/semanticTests/extracted/shift_constant_right.sol new file mode 100644 index 000000000000..766a8522e514 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_constant_right.sol @@ -0,0 +1,6 @@ +contract C { + uint256 public a = 0x4200 >> 8; +} + +// ---- +// a() -> 0x42 diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol new file mode 100644 index 000000000000..0f36c10ee0a3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol @@ -0,0 +1,9 @@ +contract C { + function f() public returns (uint256 a) { + a = 0x4200; + a >>= 8; + } +} + +// ---- +// f() -> 0x42 diff --git a/test/libsolidity/semanticTests/extracted/shift_left.sol b/test/libsolidity/semanticTests/extracted/shift_left.sol new file mode 100644 index 000000000000..15d2a972a491 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint256): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint256): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint256): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 +// f(uint256,uint256): 0x4266, 0x100 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_left_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_left_assignment.sol new file mode 100644 index 000000000000..06cb386067be --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left_assignment.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + a <<= b; + return a; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint256): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint256): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint256): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 +// f(uint256,uint256): 0x4266, 0x100 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol new file mode 100644 index 000000000000..5cc15c1a85e3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol @@ -0,0 +1,13 @@ +contract C { + function f(uint256 a, uint8 b) public returns (uint256) { + a <<= b; + return a; + } +} + +// ---- +// f(uint256,uint8): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint8): 0x4266, 0x8 -> 0x426600 +// f(uint256,uint8): 0x4266, 0x10 -> 0x42660000 +// f(uint256,uint8): 0x4266, 0x11 -> 0x84cc0000 +// f(uint256,uint8): 0x4266, 0xf0 -> 0x4266000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol b/test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol new file mode 100644 index 000000000000..99ff376d6a63 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol @@ -0,0 +1,11 @@ +// This basically tests proper cleanup and conversion. It should not convert x to int8. +contract C { + function f() public returns (int8) { + uint8 x = 254; + int8 y = 1; + return y << x; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_left_uint32.sol b/test/libsolidity/semanticTests/extracted/shift_left_uint32.sol new file mode 100644 index 000000000000..0f35077b15de --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left_uint32.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint32 a, uint32 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint32,uint32): 0x4266, 0x0 -> 0x4266 +// f(uint32,uint32): 0x4266, 0x8 -> 0x426600 +// f(uint32,uint32): 0x4266, 0x10 -> 0x42660000 +// f(uint32,uint32): 0x4266, 0x11 -> 0x84cc0000 +// f(uint32,uint32): 0x4266, 0x20 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_left_uint8.sol b/test/libsolidity/semanticTests/extracted/shift_left_uint8.sol new file mode 100644 index 000000000000..3070314f8454 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_left_uint8.sol @@ -0,0 +1,9 @@ +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + return a << b; + } +} + +// ---- +// f(uint8,uint8): 0x66, 0x0 -> 0x66 +// f(uint8,uint8): 0x66, 0x8 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol new file mode 100644 index 000000000000..b92fb2229cf8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol @@ -0,0 +1,6 @@ +contract C { + int256 public a = -0x42 << 8; +} + +// ---- +// a() -> -16896 diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol new file mode 100644 index 000000000000..b084633339b9 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol @@ -0,0 +1,6 @@ +contract C { + int256 public a = -0x4200 >> 8; +} + +// ---- +// a() -> -66 diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol new file mode 100644 index 000000000000..77c18c44b1f2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol @@ -0,0 +1,13 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + return a << b; + } + + function g(int256 a, int256 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int256,int256): 1, -1 -> FAILURE +// g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol new file mode 100644 index 000000000000..e63a9a57eafb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol @@ -0,0 +1,15 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a <<= b; + return a; + } + + function g(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): 1, -1 -> FAILURE +// g(int256,int256): 1, -1 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_overflow.sol b/test/libsolidity/semanticTests/extracted/shift_overflow.sol new file mode 100644 index 000000000000..f1b4bca0a920 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_overflow.sol @@ -0,0 +1,16 @@ +contract C { + function leftU(uint8 x, uint8 y) public returns (uint8) { + return x << y; + } + + function leftS(int8 x, int8 y) public returns (int8) { + return x << y; + } +} + +// ---- +// leftU(uint8,uint8): 255, 8 -> 0 +// leftU(uint8,uint8): 255, 1 -> 254 +// leftU(uint8,uint8): 255, 0 -> 255 +// leftS(int8,int8): 1, 7 -> -128 # Result is -128 and output is sign-extended, not zero-padded. # +// leftS(int8,int8): 1, 6 -> 64 diff --git a/test/libsolidity/semanticTests/extracted/shift_right.sol b/test/libsolidity/semanticTests/extracted/shift_right.sol new file mode 100644 index 000000000000..d78d18abaeeb --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x42 +// f(uint256,uint256): 0x4266, 0x10 -> 0 +// f(uint256,uint256): 0x4266, 0x11 -> 0 +// f(uint256,uint256): 57896044618658097711785492504343953926634992332820282019728792003956564819968, 5 -> 1809251394333065553493296640760748560207343510400633813116524750123642650624 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_right_assignment.sol new file mode 100644 index 000000000000..cfee67301925 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_assignment.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint256 a, uint256 b) public returns (uint256) { + a >>= b; + return a; + } +} + +// ---- +// f(uint256,uint256): 0x4266, 0x0 -> 0x4266 +// f(uint256,uint256): 0x4266, 0x8 -> 0x42 +// f(uint256,uint256): 0x4266, 0x10 -> 0 +// f(uint256,uint256): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol new file mode 100644 index 000000000000..ba819fbcedb2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol @@ -0,0 +1,12 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): 0x4266, 0x0 -> 0x4266 +// f(int256,int256): 0x4266, 0x8 -> 0x42 +// f(int256,int256): 0x4266, 0x10 -> 0 +// f(int256,int256): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol new file mode 100644 index 000000000000..2ae9647e262e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol @@ -0,0 +1,65 @@ +contract C { + function f1() public pure returns (bool) { + return (-4266 >> 0) == -4266; + } + + function f2() public pure returns (bool) { + return (-4266 >> 1) == -2133; + } + + function f3() public pure returns (bool) { + return (-4266 >> 4) == -267; + } + + function f4() public pure returns (bool) { + return (-4266 >> 8) == -17; + } + + function f5() public pure returns (bool) { + return (-4266 >> 16) == -1; + } + + function f6() public pure returns (bool) { + return (-4266 >> 17) == -1; + } + + function g1() public pure returns (bool) { + return (-4267 >> 0) == -4267; + } + + function g2() public pure returns (bool) { + return (-4267 >> 1) == -2134; + } + + function g3() public pure returns (bool) { + return (-4267 >> 4) == -267; + } + + function g4() public pure returns (bool) { + return (-4267 >> 8) == -17; + } + + function g5() public pure returns (bool) { + return (-4267 >> 16) == -1; + } + + function g6() public pure returns (bool) { + return (-4267 >> 17) == -1; + } +} + +// ==== +// compileViaYul: also +// ---- +// f1() -> true +// f2() -> true +// f3() -> true +// f4() -> true +// f5() -> true +// f6() -> true +// g1() -> true +// g2() -> true +// g3() -> true +// g4() -> true +// g5() -> true +// g6() -> true diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol new file mode 100644 index 000000000000..73aae5bc906a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol @@ -0,0 +1,19 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int256,int256): -4266, 0 -> -4266 +// f(int256,int256): -4266, 1 -> -2133 +// f(int256,int256): -4266, 4 -> -267 +// f(int256,int256): -4266, 8 -> -17 +// f(int256,int256): -4266, 16 -> -1 +// f(int256,int256): -4266, 17 -> -1 +// f(int256,int256): -4267, 0 -> -4267 +// f(int256,int256): -4267, 1 -> -2134 +// f(int256,int256): -4267, 4 -> -267 +// f(int256,int256): -4267, 8 -> -17 +// f(int256,int256): -4267, 16 -> -1 +// f(int256,int256): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol new file mode 100644 index 000000000000..7f3beb59f1a7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol @@ -0,0 +1,20 @@ +contract C { + function f(int256 a, int256 b) public returns (int256) { + a >>= b; + return a; + } +} + +// ---- +// f(int256,int256): -4266, 0 -> -4266 +// f(int256,int256): -4266, 1 -> -2133 +// f(int256,int256): -4266, 4 -> -267 +// f(int256,int256): -4266, 8 -> -17 +// f(int256,int256): -4266, 16 -> -1 +// f(int256,int256): -4266, 17 -> -1 +// f(int256,int256): -4267, 0 -> -4267 +// f(int256,int256): -4267, 1 -> -2134 +// f(int256,int256): -4267, 4 -> -267 +// f(int256,int256): -4267, 8 -> -17 +// f(int256,int256): -4267, 16 -> -1 +// f(int256,int256): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol new file mode 100644 index 000000000000..24ab541230ae --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol @@ -0,0 +1,19 @@ +contract C { + function f(int16 a, int16 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int16,int16): -4266, 0 -> -4266 +// f(int16,int16): -4266, 1 -> -2133 +// f(int16,int16): -4266, 4 -> -267 +// f(int16,int16): -4266, 8 -> -17 +// f(int16,int16): -4266, 16 -> -1 +// f(int16,int16): -4266, 17 -> -1 +// f(int16,int16): -4267, 0 -> -4267 +// f(int16,int16): -4267, 1 -> -2134 +// f(int16,int16): -4267, 4 -> -267 +// f(int16,int16): -4267, 8 -> -17 +// f(int16,int16): -4267, 16 -> -1 +// f(int16,int16): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol new file mode 100644 index 000000000000..7ff669dc9f08 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol @@ -0,0 +1,19 @@ +contract C { + function f(int32 a, int32 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int32,int32): -4266, 0 -> -4266 +// f(int32,int32): -4266, 1 -> -2133 +// f(int32,int32): -4266, 4 -> -267 +// f(int32,int32): -4266, 8 -> -17 +// f(int32,int32): -4266, 16 -> -1 +// f(int32,int32): -4266, 17 -> -1 +// f(int32,int32): -4267, 0 -> -4267 +// f(int32,int32): -4267, 1 -> -2134 +// f(int32,int32): -4267, 4 -> -267 +// f(int32,int32): -4267, 8 -> -17 +// f(int32,int32): -4267, 16 -> -1 +// f(int32,int32): -4267, 17 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol new file mode 100644 index 000000000000..c6424f141e1b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol @@ -0,0 +1,19 @@ +contract C { + function f(int8 a, int8 b) public returns (int256) { + return a >> b; + } +} + +// ---- +// f(int8,int8): -66, 0 -> -66 +// f(int8,int8): -66, 1 -> -33 +// f(int8,int8): -66, 4 -> -5 +// f(int8,int8): -66, 8 -> -1 +// f(int8,int8): -66, 16 -> -1 +// f(int8,int8): -66, 17 -> -1 +// f(int8,int8): -67, 0 -> -67 +// f(int8,int8): -67, 1 -> -34 +// f(int8,int8): -67, 4 -> -5 +// f(int8,int8): -67, 8 -> -1 +// f(int8,int8): -67, 16 -> -1 +// f(int8,int8): -67, 17 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_uint32.sol b/test/libsolidity/semanticTests/extracted/shift_right_uint32.sol new file mode 100644 index 000000000000..03573d985c7d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_uint32.sol @@ -0,0 +1,11 @@ +contract C { + function f(uint32 a, uint32 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint32,uint32): 0x4266, 0x0 -> 0x4266 +// f(uint32,uint32): 0x4266, 0x8 -> 0x42 +// f(uint32,uint32): 0x4266, 0x10 -> 0 +// f(uint32,uint32): 0x4266, 0x11 -> 0 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_uint8.sol b/test/libsolidity/semanticTests/extracted/shift_right_uint8.sol new file mode 100644 index 000000000000..8457b10e169b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_uint8.sol @@ -0,0 +1,9 @@ +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + return a >> b; + } +} + +// ---- +// f(uint8,uint8): 0x66, 0x0 -> 0x66 +// f(uint8,uint8): 0x66, 0x8 -> 0x0 diff --git a/test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol new file mode 100644 index 000000000000..c05060b7e391 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol @@ -0,0 +1,10 @@ +contract Foo { + function getX() public returns (uint256 r) { + return x; + } + + uint256 constant x = 56; +} + +// ---- +// getX() -> 56 diff --git a/test/libsolidity/semanticTests/extracted/simple_throw.sol b/test/libsolidity/semanticTests/extracted/simple_throw.sol new file mode 100644 index 000000000000..ad88deca6c0c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/simple_throw.sol @@ -0,0 +1,11 @@ +contract Test { + function f(uint256 x) public returns (uint256) { + if (x > 10) return x + 10; + else revert(); + return 2; + } +} + +// ---- +// f(uint256): 11 -> 21 +// f(uint256): 1 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol b/test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol new file mode 100644 index 000000000000..0864121de77b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol @@ -0,0 +1,35 @@ +contract Base { + uint256 data; + + function setData(uint256 i) public { + data = i; + } + + function getViaBase() public returns (uint256 i) { + return data; + } +} + + +contract A is Base { + function setViaA(uint256 i) public { + setData(i); + } +} + + +contract B is Base { + function getViaB() public returns (uint256 i) { + return getViaBase(); + } +} + + +contract Derived is Base, B, A {} + +// ==== +// compileViaYul: also +// ---- +// getViaB() -> 0 +// setViaA(uint256): 23 -> +// getViaB() -> 23 diff --git a/test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol b/test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol new file mode 100644 index 000000000000..350ea2622142 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol @@ -0,0 +1,15 @@ +// The EVM cannot provide access to dynamically-sized return values, so we have to skip them. +contract C { + function f() public returns (uint256, uint256[] memory, uint256) { + return (7, new uint256[](2), 8); + } + + function g() public returns (uint256, uint256) { + // Previous implementation "moved" b to the second place and did not skip. + (uint256 a, , uint256 b) = this.f(); + return (a, b); + } +} + +// ---- +// g() -> 7, 8 diff --git a/test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol b/test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol new file mode 100644 index 000000000000..3b80cf973030 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol @@ -0,0 +1,22 @@ +// For accessors, the dynamic types are already removed in the external signature itself. +contract C { + struct S { + uint256 x; + string a; // this is present in the accessor + uint256[] b; // this is not present + uint256 y; + } + S public s; + + function g() public returns (uint256, uint256) { + s.x = 2; + s.a = "abc"; + s.b = [7, 8, 9]; + s.y = 6; + (uint256 x, , uint256 y) = this.s(); + return (x, y); + } +} + +// ---- +// g() -> 2, 6 diff --git a/test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol b/test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol new file mode 100644 index 000000000000..1d1036c2c8d2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol @@ -0,0 +1,20 @@ +contract C { + uint256 public x; + modifier run() { + for (uint256 i = 0; i < 10; i++) { + _; + break; + } + } + + function f() public run { + uint256 k = x; + uint256 t = k + 1; + x = t; + } +} + +// ---- +// x() -> 0 +// f() -> +// x() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol b/test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol new file mode 100644 index 000000000000..585914c804b9 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol @@ -0,0 +1,11 @@ +contract A { + uint256 x = 1; + uint256 y = 2; + + function a() public returns (uint256 x) { + x = A.y; + } +} + +// ---- +// a() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol b/test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol new file mode 100644 index 000000000000..6bef6f85a650 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol @@ -0,0 +1,10 @@ +contract Scope { + uint256 stateVar = 42; + + function getStateVar() public view returns (uint256 stateVar) { + stateVar = Scope.stateVar; + } +} + +// ---- +// getStateVar() -> 42 diff --git a/test/libsolidity/semanticTests/extracted/storage_array_ref.sol b/test/libsolidity/semanticTests/extracted/storage_array_ref.sol new file mode 100644 index 000000000000..0b0224bfc490 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/storage_array_ref.sol @@ -0,0 +1,60 @@ +contract BinarySearch { + /// Finds the position of _value in the sorted list _data. + /// Note that "internal" is important here, because storage references only work for internal or private functions + function find(uint256[] storage _data, uint256 _value) + internal + returns (uint256 o_position) + { + return find(_data, 0, _data.length, _value); + } + + function find( + uint256[] storage _data, + uint256 _begin, + uint256 _len, + uint256 _value + ) private returns (uint256 o_position) { + if (_len == 0 || (_len == 1 && _data[_begin] != _value)) + return uint256(-1); // failure + uint256 halfLen = _len / 2; + uint256 v = _data[_begin + halfLen]; + if (_value < v) return find(_data, _begin, halfLen, _value); + else if (_value > v) + return find(_data, _begin + halfLen + 1, halfLen - 1, _value); + else return _begin + halfLen; + } +} + + +contract Store is BinarySearch { + uint256[] data; + + function add(uint256 v) public { + data.push(0); + data[data.length - 1] = v; + } + + function find(uint256 v) public returns (uint256) { + return find(data, v); + } +} + +// ==== +// compileViaYul: also +// ---- +// find(uint256): 7 -> -1 +// add(uint256): 7 -> +// find(uint256): 7 -> 0 +// add(uint256): 11 -> +// add(uint256): 17 -> +// add(uint256): 27 -> +// add(uint256): 31 -> +// add(uint256): 32 -> +// add(uint256): 66 -> +// add(uint256): 177 -> +// find(uint256): 7 -> 0 +// find(uint256): 27 -> 3 +// find(uint256): 32 -> 5 +// find(uint256): 176 -> -1 +// find(uint256): 0 -> -1 +// find(uint256): 400 -> -1 diff --git a/test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol b/test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol new file mode 100644 index 000000000000..7a8a2c276218 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol @@ -0,0 +1,11 @@ +contract Test { + mapping(string => uint256) data; + + function f() public returns (uint256) { + data["abc"] = 2; + return data["abc"]; + } +} + +// ---- +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/store_bytes.sol b/test/libsolidity/semanticTests/extracted/store_bytes.sol new file mode 100644 index 000000000000..99eb1acff958 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/store_bytes.sol @@ -0,0 +1,14 @@ +// this test just checks that the copy loop does not mess up the stack +contract C { + function save() public returns (uint256 r) { + r = 23; + savedData = msg.data; + r = 24; + } + + bytes savedData; +} + +// ---- +// save() -> 24 # empty copy loop # +// save(): "abcdefg" -> 24 diff --git a/test/libsolidity/semanticTests/extracted/store_function.sol b/test/libsolidity/semanticTests/extracted/store_function.sol new file mode 100644 index 000000000000..a09404fce004 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/store_function.sol @@ -0,0 +1,28 @@ +contract Other { + function addTwo(uint256 x) public returns (uint256) { + return x + 2; + } +} + + +contract C { + function (function (uint) external returns (uint)) internal returns (uint) ev; + function (uint) external returns (uint) x; + + function store(function(uint) external returns (uint) y) public { + x = y; + } + + function eval(function(uint) external returns (uint) y) public returns (uint) { + return y(7); + } + + function t() public returns (uint256) { + ev = eval; + this.store((new Other()).addTwo); + return ev(x); + } +} + +// ---- +// t() -> 9 diff --git a/test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol b/test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol new file mode 100644 index 000000000000..ab8ad47f9be4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol @@ -0,0 +1,21 @@ +contract C { + uint256 public result_in_constructor; + function(uint256) returns (uint256) internal x; + + constructor() public { + x = double; + result_in_constructor = use(2); + } + + function double(uint256 _arg) public returns (uint256 _ret) { + _ret = _arg * 2; + } + + function use(uint256 _arg) public returns (uint256) { + return x(_arg); + } +} + +// ---- +// use(uint256): 3 -> 6 +// result_in_constructor() -> 4 diff --git a/test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol b/test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol new file mode 100644 index 000000000000..7492a42811d7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol @@ -0,0 +1,18 @@ +contract C { + function() returns (uint256) internal x; + + constructor() public { + x = unused; + } + + function unused() internal returns (uint256) { + return 7; + } + + function t() public returns (uint256) { + return x(); + } +} + +// ---- +// t() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol b/test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol new file mode 100644 index 000000000000..0a4295114f4d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol @@ -0,0 +1,21 @@ +library L { + function x() internal returns (uint256) { + return 7; + } +} + + +contract C { + function() returns (uint256) internal x; + + constructor() public { + x = L.x; + } + + function t() public returns (uint256) { + return x(); + } +} + +// ---- +// t() -> 7 diff --git a/test/libsolidity/semanticTests/extracted/string_tuples.sol b/test/libsolidity/semanticTests/extracted/string_tuples.sol new file mode 100644 index 000000000000..3269d97c0b61 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/string_tuples.sol @@ -0,0 +1,17 @@ +contract C { + function f() public returns (string memory, uint256) { + return ("abc", 8); + } + + function g() public returns (string memory, string memory) { + return (h(), "def"); + } + + function h() public returns (string memory) { + return ("abc"); + } +} + +// ---- +// f() -> 0x40, 0x8, 0x3, "abc" +// g() -> 0x40, 0x80, 0x3, "abc", 0x3, "def" diff --git a/test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol b/test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol new file mode 100644 index 000000000000..8591131be896 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol @@ -0,0 +1,36 @@ +contract test { + struct testStruct { + uint256 m_value; + } + testStruct data1; + testStruct data2; + testStruct data3; + + constructor() public { + data1.m_value = 2; + } + + function assign() + public + returns ( + uint256 ret_local, + uint256 ret_global, + uint256 ret_global3, + uint256 ret_global1 + ) + { + testStruct storage x = data1; //x is a reference data1.m_value == 2 as well as x.m_value = 2 + data2 = data1; // should copy data. data2.m_value == 2 + + ret_local = x.m_value; // = 2 + ret_global = data2.m_value; // = 2 + + x.m_value = 3; + data3 = x; //should copy the data. data3.m_value == 3 + ret_global3 = data3.m_value; // = 3 + ret_global1 = data1.m_value; // = 3. Changed due to the assignment to x.m_value + } +} + +// ---- +// assign() -> 2, 2, 3, 3 diff --git a/test/libsolidity/semanticTests/extracted/struct_copy.sol b/test/libsolidity/semanticTests/extracted/struct_copy.sol new file mode 100644 index 000000000000..f6c35f7da4e2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_copy.sol @@ -0,0 +1,48 @@ +contract c { + struct Nested { + uint256 x; + uint256 y; + } + struct Struct { + uint256 a; + mapping(uint256 => Struct) b; + Nested nested; + uint256 c; + } + mapping(uint256 => Struct) data; + + function set(uint256 k) public returns (bool) { + data[k].a = 1; + data[k].nested.x = 3; + data[k].nested.y = 4; + data[k].c = 2; + return true; + } + + function copy(uint256 from, uint256 to) public returns (bool) { + data[to] = data[from]; + return true; + } + + function retrieve(uint256 k) + public + returns (uint256 a, uint256 x, uint256 y, uint256 c) + { + a = data[k].a; + x = data[k].nested.x; + y = data[k].nested.y; + c = data[k].c; + } +} + +// ---- +// set(uint256): 7 -> true +// retrieve(uint256): 7 -> 1, 3, 4, 2 +// copy(uint256,uint256): 7, 8 -> true +// retrieve(uint256): 7 -> 1, 3, 4, 2 +// retrieve(uint256): 8 -> 1, 3, 4, 2 +// copy(uint256,uint256): 0, 7 -> true +// retrieve(uint256): 7 -> 0, 0, 0, 0 +// retrieve(uint256): 8 -> 1, 3, 4, 2 +// copy(uint256,uint256): 7, 8 -> true +// retrieve(uint256): 8 -> 0, 0, 0, 0 diff --git a/test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol b/test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol new file mode 100644 index 000000000000..a1cfcac05df5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol @@ -0,0 +1,19 @@ +contract c { + struct Struct { + uint256 a; + uint256 b; + } + Struct data1; + Struct data2; + + function test() public returns (bool) { + data1.a = 1; + data1.b = 2; + Struct memory x = data1; + data2 = x; + return data2.a == data1.a && data2.b == data1.b; + } +} + +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/extracted/struct_delete_member.sol b/test/libsolidity/semanticTests/extracted/struct_delete_member.sol new file mode 100644 index 000000000000..fbaf7b6d9e8f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_delete_member.sol @@ -0,0 +1,20 @@ +contract test { + struct testStruct { + uint256 m_value; + } + testStruct data1; + + constructor() public { + data1.m_value = 2; + } + + function deleteMember() public returns (uint256 ret_value) { + testStruct storage x = data1; //should not copy the data. data1.m_value == 2 but x.m_value = 0 + x.m_value = 4; + delete x.m_value; + ret_value = data1.m_value; + } +} + +// ---- +// deleteMember() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol b/test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol new file mode 100644 index 000000000000..59d79da9fa3a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol @@ -0,0 +1,18 @@ +contract test { + struct testStruct { + uint256 m_value; + } + mapping(uint256 => testStruct) campaigns; + + constructor() public { + campaigns[0].m_value = 2; + } + + function deleteIt() public returns (uint256) { + delete campaigns[0]; + return campaigns[0].m_value; + } +} + +// ---- +// deleteIt() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/struct_named_constructor.sol b/test/libsolidity/semanticTests/extracted/struct_named_constructor.sol new file mode 100644 index 000000000000..5368b090ea86 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_named_constructor.sol @@ -0,0 +1,14 @@ +contract C { + struct S { + uint256 a; + bool x; + } + S public s; + + constructor() public { + s = S({a: 1, x: true}); + } +} + +// ---- +// s() -> 1, true diff --git a/test/libsolidity/semanticTests/extracted/super.sol b/test/libsolidity/semanticTests/extracted/super.sol new file mode 100644 index 000000000000..16e4257e157c --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/super.sol @@ -0,0 +1,29 @@ +contract A { + function f() public virtual returns (uint256 r) { + return 1; + } +} + + +contract B is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 2; + } +} + + +contract C is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 4; + } +} + + +contract D is B, C { + function f() public override(B, C) returns (uint256 r) { + return super.f() | 8; + } +} + +// ---- +// f() -> 15 diff --git a/test/libsolidity/semanticTests/extracted/super_alone.sol b/test/libsolidity/semanticTests/extracted/super_alone.sol new file mode 100644 index 000000000000..623f25330882 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/super_alone.sol @@ -0,0 +1,10 @@ +contract A { + function f() public { + super; + } +} + +// ==== +// compileViaYul: also +// ---- +// f() -> diff --git a/test/libsolidity/semanticTests/extracted/super_in_constructor.sol b/test/libsolidity/semanticTests/extracted/super_in_constructor.sol new file mode 100644 index 000000000000..33e270c9ea1b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/super_in_constructor.sol @@ -0,0 +1,35 @@ +contract A { + function f() public virtual returns (uint256 r) { + return 1; + } +} + + +contract B is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 2; + } +} + + +contract C is A { + function f() public virtual override returns (uint256 r) { + return super.f() | 4; + } +} + + +contract D is B, C { + uint256 data; + + constructor() public { + data = super.f() | 8; + } + + function f() public override (B, C) returns (uint256 r) { + return data; + } +} + +// ---- +// f() -> 15 diff --git a/test/libsolidity/semanticTests/extracted/super_overload.sol b/test/libsolidity/semanticTests/extracted/super_overload.sol new file mode 100644 index 000000000000..6a1f6dc3d1d3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/super_overload.sol @@ -0,0 +1,27 @@ +contract A { + function f(uint256 a) public returns (uint256) { + return 2 * a; + } +} + + +contract B { + function f(bool b) public returns (uint256) { + return 10; + } +} + + +contract C is A, B { + function g() public returns (uint256) { + return super.f(true); + } + + function h() public returns (uint256) { + return super.f(1); + } +} + +// ---- +// g() -> 10 +// h() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol b/test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol new file mode 100644 index 000000000000..59907b476b7a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol @@ -0,0 +1,34 @@ +// This tests a swap in storage which does not work as one +// might expect because we do not have temporary storage. +// (x, y) = (y, x) is the same as +// y = x; +// x = y; +contract c { + struct S { + uint256 a; + uint256 b; + } + S public x; + S public y; + + function set() public { + x.a = 1; + x.b = 2; + y.a = 3; + y.b = 4; + } + + function swap() public { + (x, y) = (y, x); + } +} + +// ---- +// x() -> 0, 0 +// y() -> 0, 0 +// set() -> +// x() -> 1, 2 +// y() -> 3, 4 +// swap() -> +// x() -> 1, 2 +// y() -> 1, 2 diff --git a/test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol b/test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol new file mode 100644 index 000000000000..1f12ba390dd7 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol @@ -0,0 +1,11 @@ +contract test { + function f(bool cond) public pure returns (uint256) { + uint32 x = 0x1234_ab; + uint256 y = 0x1234_abcd_1234; + return cond ? x : y; + } +} +// ---- +// f(bool): true -> 0x1234ab +// f(bool): false -> 0x1234abcd1234 + diff --git a/test/libsolidity/semanticTests/extracted/tuples.sol b/test/libsolidity/semanticTests/extracted/tuples.sol new file mode 100644 index 000000000000..00fcd6f9a08b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/tuples.sol @@ -0,0 +1,30 @@ +contract C { + uint256[] data; + uint256[] m_c; + + function g() internal returns (uint256 a, uint256 b, uint256[] storage c) { + return (1, 2, data); + } + + function h() external returns (uint256 a, uint256 b) { + return (5, 6); + } + + function f() public returns (uint256) { + data.push(3); + uint256 a; + uint256 b; + (a, b) = this.h(); + if (a != 5 || b != 6) return 1; + uint256[] storage c = m_c; + (a, b, c) = g(); + if (a != 1 || b != 2 || c[0] != 3) return 2; + (a, b) = (b, a); + if (a != 2 || b != 1) return 3; + (a, , b, , ) = (8, 9, 10, 11, 12); + if (a != 8 || b != 10) return 4; + } +} + +// ---- +// f() -> 0 diff --git a/test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol b/test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol new file mode 100644 index 000000000000..1ab8586fcc25 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol @@ -0,0 +1,26 @@ +contract C { + struct S { + uint256 x; + } + S s; + + function g() internal returns (uint256, S storage, uint256) { + s.x = 7; + return (1, s, 2); + } + + function f() public returns (bool) { + (uint256 x1, S storage y1, uint256 z1) = g(); + if (x1 != 1 || y1.x != 7 || z1 != 2) return false; + (, S storage y2, ) = g(); + if (y2.x != 7) return false; + (uint256 x2, , ) = g(); + if (x2 != 1) return false; + (, , uint256 z2) = g(); + if (z2 != 2) return false; + return true; + } +} + +// ---- +// f() -> true diff --git a/test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol b/test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol new file mode 100644 index 000000000000..ca1055fd6e2b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol @@ -0,0 +1,11 @@ +contract Test { + function() internal x; + + function f() public returns (uint256 r) { + x(); + return 2; + } +} + +// ---- +// f() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol b/test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol new file mode 100644 index 000000000000..5d60a746650e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol @@ -0,0 +1,10 @@ +contract test { + enum Choice {A, B, C} + + function answer() public returns (test.Choice _ret) { + _ret = test.Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/using_enums.sol b/test/libsolidity/semanticTests/extracted/using_enums.sol new file mode 100644 index 000000000000..ae497f40997f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/using_enums.sol @@ -0,0 +1,16 @@ +contract test { + enum ActionChoices {GoLeft, GoRight, GoStraight, Sit} + + constructor() public { + choices = ActionChoices.GoStraight; + } + + function getChoice() public returns (uint256 d) { + d = uint256(choices); + } + + ActionChoices choices; +} + +// ---- +// getChoice() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/using_inherited_enum.sol b/test/libsolidity/semanticTests/extracted/using_inherited_enum.sol new file mode 100644 index 000000000000..c39bfe064a1e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/using_inherited_enum.sol @@ -0,0 +1,13 @@ +contract base { + enum Choice {A, B, C} +} + + +contract test is base { + function answer() public returns (Choice _ret) { + _ret = Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol b/test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol new file mode 100644 index 000000000000..0be3f80d4810 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol @@ -0,0 +1,13 @@ +contract base { + enum Choice {A, B, C} +} + + +contract test is base { + function answer() public returns (base.Choice _ret) { + _ret = base.Choice.B; + } +} + +// ---- +// answer() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/value_complex.sol b/test/libsolidity/semanticTests/extracted/value_complex.sol new file mode 100644 index 000000000000..19d11342f3cc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/value_complex.sol @@ -0,0 +1,23 @@ +contract helper { + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public payable returns (uint256 bal) { + uint256 someStackElement = 20; + return h.getBalance.value(amount).gas(1000).value(amount + 3)(); + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/extracted/value_for_constructor.sol b/test/libsolidity/semanticTests/extracted/value_for_constructor.sol new file mode 100644 index 000000000000..5cd0bc1772f8 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/value_for_constructor.sol @@ -0,0 +1,45 @@ +contract Helper { + bytes3 name; + bool flag; + + constructor(bytes3 x, bool f) public payable { + name = x; + flag = f; + } + + function getName() public returns (bytes3 ret) { + return name; + } + + function getFlag() public returns (bool ret) { + return flag; + } +} + + +contract Main { + Helper h; + + constructor() public payable { + h = (new Helper).value(10)("abc", true); + } + + function getFlag() public returns (bool ret) { + return h.getFlag(); + } + + function getName() public returns (bytes3 ret) { + return h.getName(); + } + + function getBalances() public returns (uint256 me, uint256 them) { + me = address(this).balance; + them = address(h).balance; + } +} + +// ---- +// constructor(), 22 wei -> +// getFlag() -> true +// getName() -> "abc" +// getBalances() -> 12, 10 diff --git a/test/libsolidity/semanticTests/extracted/value_insane.sol b/test/libsolidity/semanticTests/extracted/value_insane.sol new file mode 100644 index 000000000000..d74a0f7f455d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/value_insane.sol @@ -0,0 +1,22 @@ +contract helper { + function getBalance() public payable returns (uint256 myBalance) { + return address(this).balance; + } +} + + +contract test { + helper h; + + constructor() public payable { + h = new helper(); + } + + function sendAmount(uint256 amount) public returns (uint256 bal) { + return h.getBalance.value(amount).gas(1000).value(amount + 3)(); // overwrite value + } +} + +// ---- +// constructor(), 20 wei -> +// sendAmount(uint256): 5 -> 8 diff --git a/test/libsolidity/semanticTests/extracted/virtual_function_calls.sol b/test/libsolidity/semanticTests/extracted/virtual_function_calls.sol new file mode 100644 index 000000000000..33d151f82acc --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/virtual_function_calls.sol @@ -0,0 +1,22 @@ +contract Base { + function f() public returns (uint256 i) { + return g(); + } + + function g() public virtual returns (uint256 i) { + return 1; + } +} + + +contract Derived is Base { + function g() public override returns (uint256 i) { + return 2; + } +} + +// ==== +// compileViaYul: also +// ---- +// g() -> 2 +// f() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol new file mode 100644 index 000000000000..590294f15e33 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol @@ -0,0 +1,32 @@ +contract BaseBase { + uint256 m_a; + + constructor(uint256 a) public { + m_a = a; + } + + function overridden() public virtual returns (uint256 r) { + return 1; + } + + function g() public returns (uint256 r) { + return overridden(); + } +} + + +contract Base is BaseBase(BaseBase.g()) {} + + +contract Derived is Base { + function getA() public returns (uint256 r) { + return m_a; + } + + function overridden() public override returns (uint256 r) { + return 2; + } +} + +// ---- +// getA() -> 2 diff --git a/test/libsolidity/semanticTests/extracted/write_storage_external.sol b/test/libsolidity/semanticTests/extracted/write_storage_external.sol new file mode 100644 index 000000000000..0bbe522484da --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/write_storage_external.sol @@ -0,0 +1,40 @@ +contract C { + uint256 public x; + + function f(uint256 y) public payable { + x = y; + } + + function g(uint256 y) external { + x = y; + } + + function h() public { + this.g(12); + } +} + + +contract D { + C c = new C(); + + function f() public payable returns (uint256) { + c.g(3); + return c.x(); + } + + function g() public returns (uint256) { + c.g(8); + return c.x(); + } + + function h() public returns (uint256) { + c.h(); + return c.x(); + } +} + +// ---- +// f() -> 3 +// g() -> 8 +// h() -> 12 From df8e762bf9a280ca5570cb6012bb4c4256adfcff Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 16 Mar 2020 11:12:50 -0500 Subject: [PATCH 086/165] Add tools: create_traces.sh, remove-testcases.py & verify-testcases.py --- scripts/endToEndExtraction/create_traces.sh | 22 ++ .../endToEndExtraction/remove-testcases.py | 183 +++++++++++++++ .../endToEndExtraction/verify-testcases.py | 215 ++++++++++++++++++ 3 files changed, 420 insertions(+) create mode 100755 scripts/endToEndExtraction/create_traces.sh create mode 100755 scripts/endToEndExtraction/remove-testcases.py create mode 100755 scripts/endToEndExtraction/verify-testcases.py diff --git a/scripts/endToEndExtraction/create_traces.sh b/scripts/endToEndExtraction/create_traces.sh new file mode 100755 index 000000000000..f167fee5ec10 --- /dev/null +++ b/scripts/endToEndExtraction/create_traces.sh @@ -0,0 +1,22 @@ +BASE_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 || exit ; pwd -P )" + +mkdir -p build +cd build || exit +cmake ../../../ +make soltest +cd test/ || exit +echo "running soltest on 'semanticTests/extracted'..." +./soltest --color_output=false --log_level=test_suite -t semanticTests/extracted/ -- --testpath ${BASE_PATH}/../../test --no-smt --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages --show-metadata > ${BASE_PATH}/extracted-tests.trace +echo "running soltest on 'semanticTests/extracted'... done" + +cd $BASE_PATH || exit +git clone git@github.com:ethereum/solidity.git solidity-develop +cd solidity-develop || exit +mkdir -p build +cd build || exit +cmake .. +make soltest +cd test/ || exit +echo "running soltest on 'SolidityEndToEndTest'..." +./soltest --color_output=false --log_level=test_suite -t SolidityEndToEndTest/ -- --testpath ${BASE_PATH}/solidity-develop/test --no-smt --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages --show-metadata > ${BASE_PATH}/endToEndExtraction-tests.trace +echo "running soltest on 'SolidityEndToEndTest'... done" diff --git a/scripts/endToEndExtraction/remove-testcases.py b/scripts/endToEndExtraction/remove-testcases.py new file mode 100755 index 000000000000..89f50d0e1bd3 --- /dev/null +++ b/scripts/endToEndExtraction/remove-testcases.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +# pylint: disable=consider-using-enumerate, import-error + +import re +import os +import sys +import getopt +import tempfile +from getkey import getkey + + +def parse_call(call): + function = '' + arguments = "" + results = "" + search = re.search(r'// (.*):(.*)\s->\s(.*)', call, re.MULTILINE | re.DOTALL) + if search: + function = search.group(1) + arguments = search.group(2) + results = search.group(3) + if results.find("#") != -1: + results = results[:results.find("#")] + else: + search = re.search(r'// (.*)(.*)\s->\s(.*)', call, re.MULTILINE | re.DOTALL) + if search: + function = search.group(1) + arguments = search.group(2) + results = search.group(3) + if results.find("#") != -1: + results = results[:results.find("#")] + if function.find("wei") >= 0: + function = function[:function.find(",")] + return function.strip(), arguments.strip(), results.strip() + + +def colorize(left, right, id): + red = "\x1b[31m" + yellow = "\x1b[33m" + reset = "\x1b[0m" + colors = [red, yellow] + color = colors[id % len(colors)] + function, arguments, results = parse_call(right) + left = left.replace("compileAndRun", color + "compileAndRun" + reset) + right = right.replace("constructor", color + "constructor" + reset) + if function: + left = left.replace(function, color + function + reset) + right = right.replace(function, color + function + reset) + if left.find(function): + bottom = " " * (left.find(function) - 4) + right + else: + bottom = " " + right + return " " + left + "\n" + bottom # " {:<90} {:<90}\n{}".format(left, right, bottom) + + +def get_checks(content, sol_file_path): + constructors = [] + checks = [] + for line in content.split("\n"): + line = line.strip() + if line.startswith("compileAndRun"): + constructors.append(line) + if line.startswith("ABI_CHECK") or line.startswith("BOOST_REQUIRE"): + checks.append(line) + sol_file = open(sol_file_path, "r") + sol_constructors = [] + sol_checks = [] + inside_expectations = False + for line in sol_file.readlines(): + if line.startswith("// constructor()"): + sol_constructors.append(line) + elif inside_expectations and line.startswith("// "): + sol_checks.append(line) + if line.startswith("// ----"): + inside_expectations = True + sol_file.close() + if len(constructors) == len(sol_constructors) == 1: + checks.insert(0, constructors[0]) + sol_checks.insert(0, sol_constructors[0]) + return checks, sol_checks + + +def show_test(name, content, sol_file_path, current_test, test_count): + cpp_file = tempfile.NamedTemporaryFile(delete=False) + cpp_file.write(content.encode()) + cpp_file.close() + + os.system("clear") + print(str(current_test) + " / " + str(test_count) + " - " + name + "\n") + diff_env = os.getenv('DIFF', "/usr/local/bin/colordiff -a -d -w -y -W 200 ") + os.system(diff_env + " " + cpp_file.name + " " + sol_file_path) + os.unlink(cpp_file.name) + print("\n") + + checks, sol_checks = get_checks(content, sol_file_path) + + if len(checks) == len(sol_checks): + for i in range(0, len(checks)): + print(colorize(checks[i].strip(), sol_checks[i].strip(), i)) + else: + print("warning: check count not matching. this should not happen!") + + what = "" + print("\nContinue? (ENTER) Abort? (ANY OTHER KEY)") + while what != '\n': + what = getkey() + if what != '\n': + sys.exit(0) + print() + + +def get_tests(e2e_path): + tests = [] + for f in os.listdir(e2e_path): + if f.endswith(".sol"): + tests.append(f.replace(".sol", "")) + return tests + + +def process_input_file(e2e_path, input_file, interactive): + tests = get_tests(e2e_path) + cpp_file = open(input_file, "r") + inside_test = False + test_name = "" + inside_extracted_test = False + new_lines = 0 + count = 0 + test_content = "" + for line in cpp_file.readlines(): + test = re.search(r'BOOST_AUTO_TEST_CASE\((.*)\)', line, re.M | re.I) + if test: + test_name = test.group(1) + inside_test = True + inside_extracted_test = inside_test & (test_name in tests) + if inside_extracted_test: + count = count + 1 + + if interactive and inside_extracted_test: + test_content = test_content + line + + if not inside_extracted_test: + if line == "\n": + new_lines = new_lines + 1 + else: + new_lines = 0 + if not interactive and new_lines <= 1: + sys.stdout.write(line) + + if line == "}\n": + if interactive and inside_extracted_test: + show_test(test_name, test_content.strip(), e2e_path + "/" + test_name + ".sol", count, len(tests)) + test_content = "" + inside_test = False + cpp_file.close() + sys.stdout.flush() + + +def main(argv): + interactive = False + input_file = None + try: + opts, args = getopt.getopt(argv, "if:") + except getopt.GetoptError: + print("./remove-testcases.py [-i] [-f ]") + sys.exit(1) + + for opt, arg in opts: + if opt == '-i': + interactive = True + elif opt in '-f': + input_file = arg + + base_path = os.path.dirname(__file__) + + if not input_file: + input_file = base_path + "/../../test/libsolidity/SolidityEndToEndTest.cpp" + + e2e_path = base_path + "/../../test/libsolidity/semanticTests/extracted" + + process_input_file(e2e_path, input_file, interactive) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py new file mode 100755 index 000000000000..87dc309d8ceb --- /dev/null +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# +# - SolidityEndToEndTest.trace was created with soltest with the following command on +# ./soltest --color_output=false --log_level=test_suite -t SolidityEndToEndTest/ -- --no-smt +# --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages > SolidityEndToEndTest.trace +# - a trace of the semantic tests can be created by using +# ./soltest --color_output=false --log_level=test_suite -t semanticTests/extracted/ -- --no-smt +# --evmonepath /Users/alex/evmone/lib/libevmone.dylib --show-messages > semanticTests.trace +# +# verify-testcases.py will compare both traces. If these traces are identical, the extracted tests where +# identical with the tests specified in SolidityEndToEndTest.cpp. +# +# pylint: disable=too-many-instance-attributes + +import re +import os +import sys +import getopt +import json + + +class Trace: + def __init__(self, kind, parameter): + self.kind = kind + self.parameter = parameter + self._input = "" + self._output = "" + self.value = "" + self.result = "" + self.gas = "" + + def get_input(self): + return self._input + + def set_input(self, input): + if self.kind == "create": + # remove cbor encoded metadata from bytecode + length = int(input[-4:], 16) * 2 + self._input = input[:len(input) - length - 4] + + def get_output(self): + return self._output + + def set_output(self, output): + if self.kind == "create": + # remove cbor encoded metadata from bytecode + length = int(output[-4:], 16) * 2 + self._output = output[:len(output) - length - 4] + + def __str__(self): + # we ignore the used gas + result = str( + "kind='" + self.kind + "' parameter='" + self.parameter + "' input='" + self._input + + "' output='" + self._output + "' value='" + self.value + "' result='" + self.result + "'" + ) + return result + + +class TestCase: + def __init__(self, name): + self.name = name + self.metadata = None + self.traces = [] + + def add_trace(self, kind, parameter): + trace = Trace(kind, parameter) + self.traces.append(trace) + return trace + + +class TraceAnalyser: + def __init__(self, file): + self.file = file + self.tests = {} + self.ready = False + + def analyse(self): + trace_file = open(self.file, "r") + trace = None + test_case = None + for line in trace_file.readlines(): + test = re.search(r'Entering test case "(.*)"', line, re.M | re.I) + if test: + test_name = test.group(1) + test_case = TestCase(test_name) + self.tests[test_name] = test_case + + metadata = re.search(r'\s*metadata:\s*(.*)$', line, re.M | re.I) + if metadata: + test_case.metadata = json.loads(metadata.group(1)) + del test_case.metadata["sources"] + del test_case.metadata["compiler"]["version"] + + create = re.search(r'CREATE\s*([a-fA-F0-9]*):', line, re.M | re.I) + if create: + trace = test_case.add_trace("create", create.group(1)) + + call = re.search(r'CALL\s*([a-fA-F0-9]*)\s*->\s*([a-fA-F0-9]*):', line, re.M | re.I) + if call: + trace = test_case.add_trace("call", call.group(1)) # + "->" + call.group(2)) + + if not create and not call: + self.parse_parameters(line, trace) + + trace_file.close() + + print(self.file + ":", len(self.tests), "test-cases.") + + self.ready = True + + @staticmethod + def parse_parameters(line, trace): + input = re.search(r'\s*in:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if input: + trace.input = input.group(1) + output = re.search(r'\s*out:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if output: + trace.output = output.group(1) + result = re.search(r'\s*result:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if result: + trace.result = result.group(1) + gas_used = re.search(r'\s*gas\sused:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if gas_used: + trace.gas = gas_used.group(1) + value = re.search(r'\s*value:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if value: + trace.value = value.group(1) + + def diff(self, analyser): + if not self.ready: + self.analyse() + if not analyser.ready: + analyser.analyse() + + intersection = set(self.tests.keys()) & set(analyser.tests.keys()) + mismatches = set() + + for test_name in intersection: + left = self.tests[test_name] + right = analyser.tests[test_name] + if json.dumps(left.metadata) != json.dumps(right.metadata): + mismatches.add( + (test_name, "metadata where different: " + json.dumps(left.metadata) + " != " + json.dumps( + right.metadata))) + if len(left.traces) != len(right.traces): + mismatches.add((test_name, "trace count are different: " + str(len(left.traces)) + + " != " + str(len(right.traces)))) + else: + self.check_traces(test_name, left, right, mismatches) + + for mismatch in mismatches: + print(mismatch[0]) + print(mismatch[1]) + + print(len(intersection), "test-cases - ", len(mismatches), " mismatche(s)") + + def check_traces(self, test_name, left, right, mismatches): + for trace_id in range(0, len(left.traces)): + left_trace = left.traces[trace_id] + right_trace = right.traces[trace_id] + assert (left_trace.kind == right_trace.kind) + if str(left_trace) != str(right_trace): + mismatch_info = " " + str(left_trace) + "\n" + mismatch_info += " " + str(right_trace) + "\n" + mismatch_info += " " + for ch in range(0, len(str(left_trace))): + if ch < len(str(left_trace)) and ch < len(str(right_trace)): + if str(left_trace)[ch] != str(right_trace)[ch]: + mismatch_info += "|" + else: + mismatch_info += " " + else: + mismatch_info += "|" + mismatch_info += "\n" + mismatches.add((test_name, mismatch_info)) + + +def main(argv): + extracted_tests_trace_file = None + end_to_end_trace_file = None + try: + opts, args = getopt.getopt(argv, "s:e:") + except getopt.GetoptError: + print("verify-testcases.py [-s ] [-e ]") + sys.exit(2) + + for opt, arg in opts: + if opt in '-s': + extracted_tests_trace_file = arg + elif opt in '-e': + end_to_end_trace_file = arg + + base_path = os.path.dirname(__file__) + if not extracted_tests_trace_file: + extracted_tests_trace_file = base_path + "/extracted-tests.trace" + if not end_to_end_trace_file: + end_to_end_trace_file = base_path + "/endToEndExtraction-tests.trace" + + for f in [extracted_tests_trace_file, end_to_end_trace_file]: + if not os.path.isfile(f): + print("trace file '" + f + "' not found. aborting.") + sys.exit(1) + + if not os.path.isfile(extracted_tests_trace_file): + print("semantic trace file '" + extracted_tests_trace_file + "' not found. aborting.") + sys.exit(1) + + semantic_trace = TraceAnalyser(extracted_tests_trace_file) + end_to_end_trace = TraceAnalyser(end_to_end_trace_file) + + semantic_trace.diff(end_to_end_trace) + + +if __name__ == "__main__": + main(sys.argv[1:]) From 50c22f080004b16f7405e420507689aab5c52947 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Tue, 28 Jan 2020 16:34:38 +0100 Subject: [PATCH 087/165] Adds script which compiles docs example with minimum compiler version. --- .circleci/config.yml | 5 ++ docs/050-breaking-changes.rst | 12 +-- docs/abi-spec.rst | 6 +- docs/assembly.rst | 4 +- docs/contracts/abstract-contracts.rst | 2 +- docs/contracts/functions.rst | 2 +- docs/contracts/inheritance.rst | 16 ++-- docs/contracts/interfaces.rst | 4 +- docs/contracts/libraries.rst | 10 ++- docs/contracts/using-for.rst | 2 +- docs/contracts/visibility-and-getters.rst | 6 +- docs/control-structures.rst | 14 ++-- docs/examples/blind-auction.rst | 2 +- docs/examples/micropayment.rst | 2 +- docs/examples/modular.rst | 2 +- docs/examples/safe-remote.rst | 2 +- docs/introduction-to-smart-contracts.rst | 2 +- docs/layout-of-source-files.rst | 2 +- docs/security-considerations.rst | 4 +- docs/style-guide.rst | 14 ++-- docs/types/mapping-types.rst | 4 +- docs/types/reference-types.rst | 8 +- docs/types/value-types.rst | 3 +- docs/using-the-compiler.rst | 2 +- scripts/common_cmdline.sh | 79 +++++++++++++++++++ scripts/docs_version_pragma_check.sh | 95 +++++++++++++++++++++++ test/cmdlineTests.sh | 55 +------------ 27 files changed, 244 insertions(+), 115 deletions(-) create mode 100644 scripts/common_cmdline.sh create mode 100755 scripts/docs_version_pragma_check.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 0319ca1529fe..6115f364435e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -122,6 +122,10 @@ defaults: name: command line tests command: ./test/cmdlineTests.sh + - run_docs_version_pragma_check: &run_docs_version_pragma_check + name: docs version pragma check + command: ./scripts/docs_version_pragma_check.sh + - test_ubuntu1604_clang: &test_ubuntu1604_clang docker: - image: ethereum/solidity-buildpack-deps:ubuntu1604-clang-ossfuzz-<< pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image-rev >> @@ -605,6 +609,7 @@ jobs: - attach_workspace: at: build - run: *run_cmdline_tests + - run: *run_docs_version_pragma_check - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index ede846cc399c..9461cb6bd6bd 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -292,8 +292,9 @@ Consider you have the following pre-0.5.0 contract already deployed: :: - // This will not compile with the current version of the compiler pragma solidity ^0.4.25; + // This will report a warning until version 0.4.25 of the compiler + // This will not compile after 0.5.0 contract OldContract { function someOldFunction(uint8 a) { //... @@ -369,8 +370,8 @@ Old version: :: - // This will not compile pragma solidity ^0.4.25; + // This will not compile after 0.5.0 contract OtherContract { uint x; @@ -396,7 +397,7 @@ Old version: // Throw is fine in this version. if (x > 100) throw; - bytes b = new bytes(x); + bytes memory b = new bytes(x); y = -3 >> 1; // y == -1 (wrong, should be -2) do { @@ -431,14 +432,15 @@ New version: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.5.0 <0.5.99; + // This will not compile after 0.6.0 contract OtherContract { uint x; function f(uint y) external { x = y; } - receive() payable external {} + function() payable external {} } contract New { diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index a3bd78319a5d..d645a3d44d33 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -234,7 +234,6 @@ Given the contract: pragma solidity >=0.4.16 <0.7.0; - contract Foo { function bar(bytes3[2] memory) public pure {} function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; } @@ -583,12 +582,11 @@ As an example, the code pragma solidity >=0.4.19 <0.7.0; pragma experimental ABIEncoderV2; - contract Test { struct S { uint a; uint[] b; T[] c; } struct T { uint x; uint y; } - function f(S memory s, T memory t, uint a) public {} - function g() public returns (S memory s, T memory t, uint a) {} + function f(S memory, T memory, uint) public pure {} + function g() public pure returns (S memory, T memory, uint) {} } would result in the JSON: diff --git a/docs/assembly.rst b/docs/assembly.rst index f908c0f5769c..19e4449e6c12 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -41,7 +41,7 @@ without a compiler change. .. code:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; library GetCode { function at(address _addr) public view returns (bytes memory o_code) { @@ -136,7 +136,7 @@ Local Solidity variables are available for assignments, for example: .. code:: - pragma solidity >=0.4.11 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; contract C { uint b; diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst index 51db0dfbedeb..7b9f8325613b 100644 --- a/docs/contracts/abstract-contracts.rst +++ b/docs/contracts/abstract-contracts.rst @@ -13,7 +13,7 @@ This can be done by using the ``abstract`` keyword as shown in the following exa defined as abstract, because the function ``utterance()`` was defined, but no implementation was provided (no implementation body ``{ }`` was given).:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; abstract contract Feline { function utterance() public virtual returns (bytes32); diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 661663028148..8b9e7df6439f 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -335,7 +335,7 @@ operations as long as there is enough gas passed on to it. :: - pragma solidity >0.6.1 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; contract Test { // This function is called for all messages sent to diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index 18c369df4f8d..d3dd0f1647db 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -154,7 +154,7 @@ A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it explicitly in the final override, but this function will bypass ``Base1.destroy``. The way around this is to use ``super``:: - pragma solidity >=0.4.22 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract owned { constructor() public { owner = msg.sender; } @@ -204,7 +204,7 @@ use the ``override`` keyword in the function header as shown in this example: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Base { @@ -227,7 +227,7 @@ bases, it has to explicitly override it: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Base1 { @@ -253,7 +253,7 @@ that already overrides all other functions. :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract A { function f() public pure{} } contract B is A {} @@ -293,7 +293,7 @@ of the variable: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract A { @@ -324,7 +324,7 @@ and the ``override`` keyword must be used in the overriding modifier: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Base { @@ -342,7 +342,7 @@ explicitly: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Base1 { @@ -498,7 +498,7 @@ One area where inheritance linearization is especially important and perhaps not :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; contract Base1 { constructor() public {} diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index 727809460127..bce974502f90 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -22,7 +22,7 @@ Interfaces are denoted by their own keyword: :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; interface Token { enum TokenType { Fungible, NonFungible } @@ -42,7 +42,7 @@ inheritance. :: - pragma solidity >0.6.1 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; interface ParentA { function test() external returns (uint256); diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 803e53f081df..86561ea7b2e4 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -47,12 +47,14 @@ more advanced example to implement a set). :: - pragma solidity >=0.4.22 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; // We define a new struct datatype that will be used to // hold its data in the calling contract. - struct Data { mapping(uint => bool) flags; } + struct Data { + mapping(uint => bool) flags; + } library Set { // Note that the first parameter is of type "storage @@ -123,7 +125,7 @@ custom types without the overhead of external function calls: :: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; struct bigint { uint[] limbs; @@ -237,7 +239,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow :: - pragma solidity >0.5.13 <0.7.0; + pragma solidity >=0.5.14 <0.7.0; library L { function f(uint256) external {} diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst index 32aa71799822..9e63abcf4ed7 100644 --- a/docs/contracts/using-for.rst +++ b/docs/contracts/using-for.rst @@ -29,7 +29,7 @@ may only be used inside a contract, not inside any of its functions. Let us rewrite the set example from the :ref:`libraries` in this way:: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; // This is the same code as before, just without comments diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst index 3a0905155f10..5ef105784b08 100644 --- a/docs/contracts/visibility-and-getters.rst +++ b/docs/contracts/visibility-and-getters.rst @@ -68,7 +68,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; contract C { uint private data; @@ -112,7 +112,7 @@ when they are declared. :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; contract C { uint public data = 42; @@ -151,7 +151,7 @@ to write a function, for example: :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; contract arrayExample { // public state variable diff --git a/docs/control-structures.rst b/docs/control-structures.rst index d5448d0b30ed..7bbe290ba35e 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -41,7 +41,7 @@ Internal Function Calls Functions of the current contract can be called directly ("internally"), also recursively, as seen in this nonsensical example:: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; contract C { function g(uint a) public pure returns (uint ret) { return a + f(); } @@ -82,7 +82,7 @@ to the total balance of that contract: :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; contract InfoFeed { function info() public payable returns (uint ret) { return 42; } @@ -160,7 +160,7 @@ Those parameters will still be present on the stack, but they are inaccessible. :: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; contract C { // omitted name for parameter @@ -183,7 +183,7 @@ is compiled so recursive creation-dependencies are not possible. :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; contract D { uint public x; @@ -238,7 +238,7 @@ which only need to be created if there is a dispute. :: - pragma solidity >0.6.1 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; contract D { uint public x; @@ -307,7 +307,7 @@ groupings of expressions. :: - pragma solidity >0.4.23 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract C { uint index; @@ -352,7 +352,7 @@ because only a reference and not a copy is passed. :: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; contract C { uint[20] x; diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index 92a7559738f8..4461bfc654f9 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -24,7 +24,7 @@ to receive their money - contracts cannot activate themselves. :: - pragma solidity >=0.4.22 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract SimpleAuction { // Parameters of the auction. Times are either diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index fe310f37a376..cd4084c84349 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -338,7 +338,7 @@ The full contract :: - pragma solidity >=0.4.24 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract SimplePaymentChannel { address payable public sender; // The account sending payments. diff --git a/docs/examples/modular.rst b/docs/examples/modular.rst index a3d932b099e6..a95a675c61ff 100644 --- a/docs/examples/modular.rst +++ b/docs/examples/modular.rst @@ -19,7 +19,7 @@ and the sum of all balances is an invariant across the lifetime of the contract. :: - pragma solidity >=0.4.22 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; library Balances { function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal { diff --git a/docs/examples/safe-remote.rst b/docs/examples/safe-remote.rst index d79c6526e36f..caafaa7edbbe 100644 --- a/docs/examples/safe-remote.rst +++ b/docs/examples/safe-remote.rst @@ -25,7 +25,7 @@ you can use state machine-like constructs inside a contract. :: - pragma solidity >=0.4.22 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract Purchase { uint public value; diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index fada5d2916af..a5f056493b6f 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -17,7 +17,7 @@ Storage Example :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; contract SimpleStorage { uint storedData; diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 1fec22aec7ea..a2629319bd90 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -284,7 +284,7 @@ for the two function parameters and two return variables. :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.21 <0.7.0; /** @title Shape calculator. */ contract ShapeCalculator { diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 829aab9e4f40..b4737049351b 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -81,7 +81,7 @@ as it uses ``call`` which forwards all remaining gas by default: :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.6.2 <0.7.0; // THIS CONTRACT CONTAINS A BUG - DO NOT USE contract Fund { @@ -277,7 +277,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The :: - pragma solidity >=0.5.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Map { mapping (uint => uint)[] array; diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 11ddaef07957..c637c8379cb2 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -109,7 +109,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; abstract contract A { function spam() virtual pure public; @@ -326,7 +326,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity ^0.6.0; contract A { @@ -745,7 +745,7 @@ manner as modifiers if the function declaration is long or hard to read. Yes:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; // Base contracts just to make this compile contract B { @@ -777,7 +777,7 @@ Yes:: No:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; // Base contracts just to make this compile @@ -1000,7 +1000,7 @@ As shown in the example below, if the contract name is `Congress` and the librar Yes:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; // Owned.sol @@ -1034,7 +1034,7 @@ and in ``Congress.sol``:: No:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; // owned.sol @@ -1138,7 +1138,7 @@ multiline comment starting with `/**` and ending with `*/`. For example, the contract from `a simple smart contract `_ with the comments added looks like the one below:: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.16 <0.7.0; /// @author The Solidity Team diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index acb48fb8a268..f69d25b0f6ee 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -66,7 +66,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.4.22 <0.7.0; contract MappingExample { @@ -120,7 +120,7 @@ the ``sum`` function iterates over to sum all the values. :: - pragma solidity >=0.5.99 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; struct IndexValue { uint keyIndex; uint value; } struct KeyFlag { uint key; bool deleted; } diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 15cd110ddc1d..275e8b575121 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -57,7 +57,7 @@ Data locations are not only relevant for persistency of data, but also for the s :: - pragma solidity >=0.4.0 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract C { // The data location of x is storage. @@ -268,7 +268,7 @@ Array Members :: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract ArrayContract { uint[2**20] m_aLotOfIntegers; @@ -400,7 +400,7 @@ Array slices are useful to ABI-decode secondary data passed in function paramete :: - pragma solidity >=0.4.99 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; contract Proxy { /// Address of the client contract managed by proxy i.e., this contract @@ -437,7 +437,7 @@ shown in the following example: :: - pragma solidity >=0.4.11 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; // Defines a new type with two fields. // Declaring a struct outside of a contract allows diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 8188b7121d05..80b9d548cb4a 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -650,7 +650,7 @@ External (or public) functions have the following members: Example that shows how to use the members:: - pragma solidity >=0.4.16 <0.7.0; + pragma solidity >=0.6.0 <0.7.0; // This will report a warning contract Example { @@ -670,7 +670,6 @@ Example that shows how to use internal function types:: pragma solidity >=0.4.16 <0.7.0; - library ArrayUtils { // internal functions can be used in internal library functions because // they will be part of the same code context diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index eb4ddf0c651a..12fe4b3f9917 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -687,7 +687,7 @@ The command above applies all changes as shown below. Please review them careful .. code-block:: none - pragma solidity >0.4.23; + pragma solidity >=0.6.0 <0.7.0; abstract contract Updateable { function run() public view virtual returns (bool); diff --git a/scripts/common_cmdline.sh b/scripts/common_cmdline.sh new file mode 100644 index 000000000000..1d21fe75c415 --- /dev/null +++ b/scripts/common_cmdline.sh @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------------ +# vim:ts=4:et +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016-2019 solidity contributors. +# ------------------------------------------------------------------------------ + +FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" +OLDARGS="--optimize --combined-json abi,asm,ast,bin,bin-runtime,devdoc,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" +function compileFull() +{ + local expected_exit_code=0 + local expect_output=0 + if [[ $1 = '-e' ]]; then + expected_exit_code=1 + expect_output=1 + shift; + fi + if [[ $1 = '-w' ]]; then + expect_output=1 + shift; + fi + if [[ $1 = '-o' ]]; then + expect_output=2 + shift; + fi + local args=$FULLARGS + if [[ $1 = '-v' ]]; then + if (echo $2 | grep -Po '(?<=0.4.)\d+' >/dev/null); then + patch=$(echo $2 | grep -Po '(?<=0.4.)\d+') + if (( patch < 22 )); then + args=$OLDARGS + fi + fi + shift 2 + fi + + local files="$*" + local output + + local stderr_path=$(mktemp) + + set +e + "$SOLC" ${args} ${files} >/dev/null 2>"$stderr_path" + local exit_code=$? + local errors=$(grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path") + set -e + rm "$stderr_path" + + if [[ \ + ("$exit_code" -ne "$expected_exit_code" || \ + ( $expect_output -eq 0 && -n "$errors" ) || \ + ( $expect_output -ne 0 && $expected_exit_code -eq 0 && $expect_output -ne 2 && -z "$errors" )) + ]] + then + printError "Unexpected compilation result:" + printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output" + printError "Was failure: $exit_code" + echo "$errors" + printError "While calling:" + echo "\"$SOLC\" $ARGS $files" + printError "Inside directory:" + pwd + false + fi +} diff --git a/scripts/docs_version_pragma_check.sh b/scripts/docs_version_pragma_check.sh new file mode 100755 index 000000000000..a66798841e49 --- /dev/null +++ b/scripts/docs_version_pragma_check.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2016 solidity contributors. +#------------------------------------------------------------------------------ + +# This script verifies that the examples compile with the oldest version mentioned in the pragma. +# It does not verify that it cannot be compiled with an older version +# and it also does not verify that it can be compiled with the newest version compatible with the pragma. + +set -e + +## GLOBAL VARIABLES + +REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) +SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build} +source "${REPO_ROOT}/scripts/common.sh" +source "${REPO_ROOT}/scripts/common_cmdline.sh" + +printTask "Verifying that all examples from the documentation have the correct version range..." +SOLTMPDIR=$(mktemp -d) +( + set -e + cd "$SOLTMPDIR" + "$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs + + for f in *.sol + do + # The contributors guide uses syntax tests, but we cannot + # really handle them here. + if grep -E 'DeclarationError:|// ----' "$f" >/dev/null + then + continue + fi + echo "$f" + + opts='' + # We expect errors if explicitly stated, or if imports + # are used (in the style guide) + if ( ! grep -E "This will not compile after" "$f" >/dev/null && \ + grep -E "This will not compile|import \"" "$f" >/dev/null ) + then + opts="-e" + fi + + # ignore warnings in this case + opts="$opts -o" + + # Get minimum compiler version defined by pragma + if (grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f" >/dev/null); then + version="$(grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f")" + if (echo $version | grep -Po '(?<=0.4.)\d+' >/dev/null); then + patch=$(echo $version | grep -Po '(?<=0.4.)\d+') + if (( patch < 11 )); then + version="0.4.11" # first available release on github + fi + fi + elif (grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f" >/dev/null); then + version="$(grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f")" + fi + + opts="$opts -v $version" + + solc_bin="solc-$version" + echo "$solc_bin" + if [[ ! -f "$solc_bin" ]]; then + echo "Downloading release from github..." + wget https://github.com/ethereum/solidity/releases/download/v$version/solc-static-linux + mv solc-static-linux $solc_bin + fi + + ln -sf "$solc_bin" "solc" + chmod a+x solc + + SOLC="$SOLTMPDIR/solc" + compileFull $opts "$SOLTMPDIR/$f" + done +) +rm -rf "$SOLTMPDIR" +echo "Done." \ No newline at end of file diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index ece4e581c3d7..9001c02f4817 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -33,6 +33,7 @@ set -e REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build} source "${REPO_ROOT}/scripts/common.sh" +source "${REPO_ROOT}/scripts/common_cmdline.sh" case "$OSTYPE" in msys) @@ -45,6 +46,7 @@ case "$OSTYPE" in SOLC="$REPO_ROOT/${SOLIDITY_BUILD_DIR}/solc/solc" ;; esac +echo "${SOLC}" INTERACTIVE=true if ! tty -s || [ "$CI" ] @@ -52,8 +54,6 @@ then INTERACTIVE="" fi -FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc" - # extend stack size in case we run via ASAN if [[ -n "${CIRCLECI}" ]] || [[ -n "$CI" ]]; then ulimit -s 16384 @@ -62,57 +62,6 @@ fi ## FUNCTIONS -function compileFull() -{ - local expected_exit_code=0 - local expect_output=0 - if [[ $1 = '-e' ]] - then - expected_exit_code=1 - expect_output=1 - shift; - fi - if [[ $1 = '-w' ]] - then - expect_output=1 - shift; - fi - if [[ $1 = '-o' ]] - then - expect_output=2 - shift; - fi - - local files="$*" - local output - - local stderr_path=$(mktemp) - - set +e - "$SOLC" $FULLARGS $files >/dev/null 2>"$stderr_path" - local exit_code=$? - local errors=$(grep -v -E 'Warning: This is a pre-release compiler version|Warning: Experimental features are turned on|pragma experimental ABIEncoderV2|^ +--> |^ +\||^[0-9]+ +\|' < "$stderr_path") - set -e - rm "$stderr_path" - - if [[ \ - "$exit_code" -ne "$expected_exit_code" || \ - ( $expect_output -eq 0 && -n "$errors" ) || \ - ( $expect_output -eq 1 && -z "$errors" ) \ - ]] - then - printError "Unexpected compilation result:" - printError "Expected failure: $expected_exit_code - Expected warning / error output: $expect_output" - printError "Was failure: $exit_code" - echo "$errors" - printError "While calling:" - echo "\"$SOLC\" $FULLARGS $files" - printError "Inside directory:" - pwd - false - fi -} - function ask_expectation_update() { if [ $INTERACTIVE ] From 3b9e9265591be87251fb569864f4af530a366a94 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 17 Mar 2020 23:31:56 +0100 Subject: [PATCH 088/165] Moved "step" from settings to expectations. --- test/libyul/YulOptimizerTest.cpp | 24 +------------------ test/libyul/YulOptimizerTest.h | 2 -- .../blockFlattener/basic.yul | 4 ++-- .../blockFlattener/for_stmt.yul | 4 ++-- .../blockFlattener/if_stmt.yul | 4 ++-- .../blockFlattener/many_nested_blocks.yul | 4 ++-- .../blockFlattener/switch_stmt.yul | 4 ++-- .../called_from_non_function.yul | 4 ++-- .../nested_different_names.yul | 4 ++-- .../nested_same_name.yul | 4 ++-- .../circularReferencesPruner/trivial.yul | 4 ++-- .../branches_for.yul | 4 ++-- .../branches_if.yul | 4 ++-- .../commonSubexpressionEliminator/case2.yul | 4 ++-- .../clear_not_needed.yul | 4 ++-- .../function_scopes.yul | 4 ++-- .../commonSubexpressionEliminator/loop.yul | 4 ++-- .../movable_functions.yul | 4 ++-- .../non_movable_instr.yul | 4 ++-- .../non_movable_instr2.yul | 4 ++-- .../object_access.yul | 4 ++-- .../commonSubexpressionEliminator/scopes.yul | 4 ++-- .../commonSubexpressionEliminator/smoke.yul | 4 ++-- .../commonSubexpressionEliminator/trivial.yul | 4 ++-- .../unassigned_return.yul | 4 ++-- .../unassigned_variables.yul | 4 ++-- .../variable_for_variable.yul | 4 ++-- .../add_correct_type.yul | 3 ++- .../add_correct_type_wasm.yul | 3 ++- .../clear_after_if_break.yul | 4 ++-- .../clear_after_if_continue.yul | 4 ++-- .../clear_before_for_condition.yul | 4 ++-- .../clear_before_for_post.yul | 4 ++-- .../no_opt_if_break_is_not_last.yul | 4 ++-- .../no_opt_inside_if.yul | 4 ++-- .../opt_after_terminating_if.yul | 4 ++-- .../conditionalSimplifier/opt_switch.yul | 4 ++-- .../conditionalSimplifier/smoke.yul | 4 ++-- .../clear_after_if_break.yul | 4 ++-- .../clear_after_if_continue.yul | 4 ++-- .../clear_before_for_condition.yul | 4 ++-- .../clear_before_for_post.yul | 4 ++-- .../no_opt_if_break_is_not_last.yul | 4 ++-- .../no_opt_inside_if.yul | 4 ++-- .../opt_after_terminating_if.yul | 4 ++-- .../conditionalUnsimplifier/opt_switch.yul | 4 ++-- .../conditionalUnsimplifier/smoke.yul | 4 ++-- .../constantOptimiser/difficult.yul | 4 ++-- .../constantOptimiser/gaps.yul | 3 ++- .../constantOptimiser/smallNumbers.yul | 4 ++-- .../empty_if_movable_condition.yul | 4 ++-- .../empty_if_non_movable_condition.yul | 4 ++-- .../controlFlowSimplifier/remove_leave.yul | 4 ++-- .../switch_only_default.yul | 4 ++-- .../switch_remove_empty_all.yul | 4 ++-- .../switch_remove_empty_case.yul | 4 ++-- .../switch_remove_empty_cases.yul | 4 ++-- .../switch_remove_empty_default_case.yul | 4 ++-- .../controlFlowSimplifier/switch_to_if.yul | 4 ++-- .../controlFlowSimplifier/terminating_for.yul | 4 ++-- .../terminating_for_nested.yul | 4 ++-- .../terminating_for_nested_reversed.yul | 4 ++-- .../terminating_for_revert.yul | 4 ++-- .../terminating_for_revert_plus_break.yul | 4 ++-- .../terminating_for_with_continue.yul | 4 ++-- .../deadCodeEliminator/conditional_break.yul | 4 ++-- .../deadCodeEliminator/early_break.yul | 4 ++-- .../deadCodeEliminator/early_continue.yul | 4 ++-- .../deadCodeEliminator/early_leave.yul | 4 ++-- .../deadCodeEliminator/early_revert.yul | 4 ++-- .../deadCodeEliminator/early_stop.yul | 4 ++-- .../deadCodeEliminator/for_loop_init_decl.yul | 4 ++-- .../function_after_revert.yul | 4 ++-- .../deadCodeEliminator/nested_revert.yul | 4 ++-- .../deadCodeEliminator/no_removal.yul | 4 ++-- .../deadCodeEliminator/normal_break.yul | 4 ++-- .../deadCodeEliminator/normal_continue.yul | 4 ++-- .../deadCodeEliminator/normal_stop.yul | 4 ++-- .../disambiguator/for_statement.yul | 3 ++- .../disambiguator/funtion_call.yul | 3 ++- .../disambiguator/if_statement.yul | 3 ++- .../disambiguator/long_names.yul | 3 ++- .../yulOptimizerTests/disambiguator/smoke.yul | 4 ++-- .../disambiguator/smoke_yul.yul | 3 ++- .../disambiguator/switch_statement.yul | 3 ++- .../disambiguator/variables.yul | 3 ++- .../disambiguator/variables_clash.yul | 3 ++- .../variables_inside_functions.yul | 3 ++- .../multiple_complex.yul | 4 ++-- .../equivalentFunctionCombiner/simple.yul | 4 ++-- .../simple_different_vars.yul | 4 ++-- .../switch_case_order.yul | 4 ++-- .../argument_duplication_heuristic.yul | 4 ++-- .../expressionInliner/complex_with_evm.yul | 4 ++-- .../expressionInliner/double_calls.yul | 4 ++-- .../double_recursive_calls.yul | 4 ++-- .../expressionInliner/no_inline_mload.yul | 4 ++-- .../no_move_with_sideeffects.yul | 4 ++-- .../expressionInliner/simple.yul | 3 ++- .../expressionInliner/with_args.yul | 3 ++- .../expressionJoiner/if_condition.yul | 4 ++-- .../expressionJoiner/muli_wrong_order3.yul | 4 ++-- .../expressionJoiner/multi.yul | 4 ++-- .../expressionJoiner/multi_reference.yul | 4 ++-- .../expressionJoiner/multi_wrong_order.yul | 4 ++-- .../expressionJoiner/multi_wrong_order2.yul | 4 ++-- .../no_replacement_across_blocks.yul | 4 ++-- .../no_replacement_in_loop_condition1.yul | 4 ++-- .../no_replacement_in_loop_condition2.yul | 4 ++-- .../expressionJoiner/only_assignment.yul | 4 ++-- .../expressionJoiner/reassignment.yul | 4 ++-- .../expressionJoiner/simple.yul | 4 ++-- .../expressionJoiner/single_wrong_order.yul | 4 ++-- .../expressionJoiner/smoke.yul | 4 ++-- .../expressionJoiner/switch_expression.yul | 4 ++-- .../expressionJoiner/triple.yul | 4 ++-- .../assigned_vars_multi.yul | 4 ++-- .../combine_shift_and_and.yul | 3 ++- .../combine_shift_and_and_2.yul | 3 ++- .../combine_shift_and_and_3.yul | 3 ++- .../constant_propagation.yul | 4 ++-- .../expressionSimplifier/constants.yul | 4 ++-- .../expressionSimplifier/create2_and_mask.yul | 3 ++- .../expressionSimplifier/create_and_mask.yul | 4 ++-- .../identity_rules_complex.yul | 4 ++-- .../identity_rules_negative.yul | 4 ++-- .../identity_rules_simple.yul | 4 ++-- .../including_function_calls.yul | 4 ++-- .../expressionSimplifier/inside_for.yul | 4 ++-- .../expressionSimplifier/invariant.yul | 4 ++-- .../large_byte_access.yul | 4 ++-- .../expressionSimplifier/mod_and_1.yul | 4 ++-- .../expressionSimplifier/mod_and_2.yul | 4 ++-- ...lied_function_call_different_arguments.yul | 4 ++-- ..._applied_function_call_different_names.yul | 4 ++-- ...ied_function_call_equality_not_movable.yul | 4 ++-- ...d_removes_non_constant_and_not_movable.yul | 4 ++-- .../expressionSimplifier/reassign.yul | 4 ++-- .../remove_redundant_shift_masking.yul | 3 ++- .../replace_too_large_shift.yul | 3 ++- .../expressionSimplifier/return_vars_zero.yul | 4 ++-- .../expressionSimplifier/reversed.yul | 4 ++-- .../side_effects_in_for_condition.yul | 3 ++- .../expressionSimplifier/smoke.yul | 4 ++-- .../unassigend_vars_multi.yul | 4 ++-- .../expressionSimplifier/unassigned_vars.yul | 4 ++-- .../expressionSplitter/control_flow.yul | 4 ++-- .../expressionSplitter/inside_function.yul | 4 ++-- .../expressionSplitter/object_access.yul | 4 ++-- .../expressionSplitter/smoke.yul | 4 ++-- .../expressionSplitter/switch.yul | 4 ++-- .../expressionSplitter/trivial.yul | 4 ++-- .../expressionSplitter/typed.yul | 3 ++- .../forLoopConditionIntoBody/cond_types.yul | 4 ++-- .../forLoopConditionIntoBody/empty_body.yul | 4 ++-- .../forLoopConditionIntoBody/nested.yul | 4 ++-- .../forLoopConditionIntoBody/simple.yul | 4 ++-- .../forLoopInitRewriter/complex_pre.yul | 4 ++-- .../forLoopInitRewriter/empty_pre.yul | 4 ++-- .../forLoopInitRewriter/nested.yul | 4 ++-- .../forLoopInitRewriter/simple.yul | 4 ++-- .../fullInliner/double_inline.yul | 4 ++-- .../fullInliner/inside_condition.yul | 4 ++-- .../fullInliner/large_function_multi_use.yul | 4 ++-- .../fullInliner/large_function_single_use.yul | 4 ++-- .../fullInliner/long_names.yul | 4 ++-- .../move_up_rightwards_argument.yul | 4 ++-- .../fullInliner/multi_fun.yul | 4 ++-- .../fullInliner/multi_fun_callback.yul | 4 ++-- .../fullInliner/multi_return.yul | 4 ++-- .../fullInliner/multi_return_typed.yul | 3 ++- .../no_inline_into_big_function.yul | 4 ++-- .../no_inline_into_big_global_context.yul | 4 ++-- .../fullInliner/no_inline_leave.yul | 4 ++-- .../fullInliner/no_return.yul | 4 ++-- .../fullInliner/not_inside_for.yul | 4 ++-- .../fullInliner/pop_result.yul | 4 ++-- .../fullInliner/recursion.yul | 4 ++-- .../yulOptimizerTests/fullInliner/simple.yul | 4 ++-- .../fullSimplify/constant_propagation.yul | 4 ++-- .../fullSimplify/constants.yul | 4 ++-- .../fullSimplify/identity_rules_complex.yul | 4 ++-- .../fullSimplify/identity_rules_negative.yul | 4 ++-- .../fullSimplify/identity_rules_simple.yul | 4 ++-- .../fullSimplify/including_function_calls.yul | 4 ++-- .../fullSimplify/inside_for.yul | 4 ++-- .../fullSimplify/invariant.yul | 4 ++-- .../fullSimplify/mod_and_1.yul | 4 ++-- .../fullSimplify/mod_and_2.yul | 4 ++-- ...lied_function_call_different_arguments.yul | 4 ++-- ..._applied_function_call_different_names.yul | 4 ++-- ...ied_function_call_equality_not_movable.yul | 4 ++-- ...d_removes_non_constant_and_not_movable.yul | 4 ++-- .../fullSimplify/operations.yul | 4 ++-- .../fullSimplify/reversed.yul | 4 ++-- .../fullSimplify/signextend.yul | 4 ++-- .../yulOptimizerTests/fullSimplify/smoke.yul | 4 ++-- .../yulOptimizerTests/fullSuite/abi2.yul | 3 ++- .../fullSuite/abi_example1.yul | 3 ++- .../yulOptimizerTests/fullSuite/aztec.yul | 4 ++-- .../fullSuite/clear_after_if_continue.yul | 4 ++-- .../fullSuite/devcon_example.yul | 4 ++-- .../fullSuite/loopInvariantCodeMotion.yul | 4 ++-- .../yulOptimizerTests/fullSuite/medium.yul | 4 ++-- .../fullSuite/no_move_loop_orig.yul | 4 ++-- ...remove_redundant_assignments_in_switch.yul | 4 ++-- .../reuse_vars_bug_in_simplifier.yul | 4 ++-- .../fullSuite/ssaReverse.yul | 4 ++-- .../fullSuite/ssaReverseComplex.yul | 4 ++-- .../fullSuite/stack_compressor_msize.yul | 4 ++-- .../yulOptimizerTests/fullSuite/storage.yul | 4 ++-- .../fullSuite/switch_inline.yul | 4 ++-- .../fullSuite/switch_inline_match_default.yul | 4 ++-- .../functionGrouper/already_grouped.yul | 4 ++-- .../functionGrouper/empty_block.yul | 3 ++- .../grouped_but_not_ordered.yul | 4 ++-- .../functionGrouper/multi_fun_mixed.yul | 3 ++- .../functionGrouper/nested_fun.yul | 3 ++- .../functionGrouper/single_fun.yul | 3 ++- .../functionGrouper/smoke.yul | 4 ++-- .../functionHoister/empty_block.yul | 3 ++- .../functionHoister/multi_mixed.yul | 3 ++- .../functionHoister/nested.yul | 3 ++- .../functionHoister/single.yul | 3 ++- .../functionHoister/smoke.yul | 4 ++-- .../yulOptimizerTests/loadResolver/loop.yul | 4 ++-- ...y_with_different_kinds_of_invalidation.yul | 4 ++-- .../loadResolver/memory_with_msize.yul | 4 ++-- .../loadResolver/merge_known_write.yul | 4 ++-- .../merge_known_write_with_distance.yul | 4 ++-- .../loadResolver/merge_unknown_write.yul | 4 ++-- .../loadResolver/merge_with_rewrite.yul | 4 ++-- .../loadResolver/mload_in_function.yul | 4 ++-- .../mstore_in_function_loop_body.yul | 4 ++-- .../mstore_in_function_loop_init.yul | 4 ++-- .../loadResolver/re_store_memory.yul | 4 ++-- .../loadResolver/re_store_storage.yul | 4 ++-- .../loadResolver/reassign.yul | 4 ++-- .../reassign_value_expression.yul | 4 ++-- .../loadResolver/second_mstore_with_delta.yul | 4 ++-- .../loadResolver/second_store.yul | 4 ++-- .../loadResolver/second_store_same_value.yul | 4 ++-- .../loadResolver/second_store_with_delta.yul | 4 ++-- .../side_effects_of_user_functions.yul | 4 ++-- .../yulOptimizerTests/loadResolver/simple.yul | 4 ++-- .../loadResolver/simple_memory.yul | 4 ++-- .../loadResolver/staticcall.yul | 3 ++- .../dependOnVarInLoop.yul | 4 ++-- .../loopInvariantCodeMotion/multi.yul | 4 ++-- .../loopInvariantCodeMotion/no_move_loop.yul | 4 ++-- .../no_move_recursive_function.yul | 4 ++-- .../loopInvariantCodeMotion/non-ssavar.yul | 4 ++-- .../loopInvariantCodeMotion/nonMovable.yul | 4 ++-- .../loopInvariantCodeMotion/recursive.yul | 4 ++-- .../loopInvariantCodeMotion/simple.yul | 4 ++-- .../mainFunction/empty_block.yul | 3 ++- .../mainFunction/multi_fun_mixed.yul | 3 ++- .../mainFunction/nested_fun.yul | 3 ++- .../mainFunction/single_fun.yul | 3 ++- .../yulOptimizerTests/mainFunction/smoke.yul | 3 ++- .../nameDisplacer/funtion_call.yul | 4 ++-- .../nameDisplacer/variables.yul | 4 ++-- .../variables_inside_functions.yul | 4 ++-- .../redundantAssignEliminator/for.yul | 4 ++-- .../redundantAssignEliminator/for_branch.yul | 4 ++-- .../redundantAssignEliminator/for_break.yul | 4 ++-- .../for_continue.yul | 4 ++-- .../for_continue_2.yul | 4 ++-- .../for_continue_3.yul | 4 ++-- .../for_decl_inside_break_continue.yul | 4 ++-- .../for_deep_noremove.yul | 4 ++-- .../for_deep_simple.yul | 4 ++-- .../for_multi_break.yul | 4 ++-- .../redundantAssignEliminator/for_nested.yul | 4 ++-- .../redundantAssignEliminator/for_rerun.yul | 4 ++-- .../for_stmnts_after_break_continue.yul | 4 ++-- .../redundantAssignEliminator/function.yul | 4 ++-- .../redundantAssignEliminator/if.yul | 4 ++-- .../if_overwrite_all_branches.yul | 4 ++-- .../if_used_in_one_branch.yul | 4 ++-- .../redundantAssignEliminator/leave.yul | 4 ++-- .../multi_assign.yul | 4 ++-- .../redundantAssignEliminator/multivar.yul | 4 ++-- .../redundantAssignEliminator/non_movable.yul | 4 ++-- .../remove_break.yul | 4 ++-- .../remove_continue.yul | 4 ++-- .../redundantAssignEliminator/scopes.yul | 4 ++-- .../redundantAssignEliminator/simple.yul | 4 ++-- .../switch_overwrite_in_all.yul | 4 ++-- .../switch_overwrite_in_one.yul | 4 ++-- .../switch_overwrite_use_combination.yul | 4 ++-- .../switch_unused.yul | 4 ++-- .../rematerialiser/branches_for1.yul | 4 ++-- .../rematerialiser/branches_for2.yul | 4 ++-- .../rematerialiser/branches_if.yul | 4 ++-- .../rematerialiser/branches_switch.yul | 4 ++-- .../rematerialiser/cheap_caller.yul | 4 ++-- .../do_not_move_out_of_scope.yul | 4 ++-- ...mat_large_amounts_of_code_if_used_once.yul | 4 ++-- .../rematerialiser/for_break.yul | 4 ++-- .../rematerialiser/for_continue.yul | 4 ++-- .../rematerialiser/for_continue_2.yul | 4 ++-- .../for_continue_with_assignment_in_post.yul | 4 ++-- .../rematerialiser/large_constant.yul | 4 ++-- .../large_constant_used_once.yul | 4 ++-- .../many_refs_small_cost_loop.yul | 4 ++-- .../rematerialiser/medium_sized_constant.yul | 4 ++-- .../rematerialiser/no_remat_in_loop.yul | 4 ++-- .../rematerialiser/non_movable_function.yul | 4 ++-- .../non_movable_instruction.yul | 4 ++-- .../rematerialiser/reassign.yul | 4 ++-- .../rematerialiser/reassignment.yul | 4 ++-- .../rematerialiser/smoke.yul | 4 ++-- .../some_refs_small_cost_loop.yul | 4 ++-- .../some_refs_small_cost_nested_loop.yul | 4 ++-- .../rematerialiser/trivial.yul | 4 ++-- .../rematerialiser/update_asignment_remat.yul | 4 ++-- .../splitJoin/control_flow.yul | 4 ++-- .../yulOptimizerTests/splitJoin/functions.yul | 4 ++-- .../yulOptimizerTests/splitJoin/smoke.yul | 4 ++-- .../yulOptimizerTests/ssaAndBack/for_loop.yul | 4 ++-- .../ssaAndBack/multi_assign.yul | 4 ++-- .../ssaAndBack/multi_assign_if.yul | 4 ++-- .../ssaAndBack/multi_assign_multi_var_if.yul | 4 ++-- .../multi_assign_multi_var_switch.yul | 4 ++-- .../ssaAndBack/multi_assign_switch.yul | 4 ++-- .../yulOptimizerTests/ssaAndBack/simple.yul | 4 ++-- .../ssaAndBack/single_assign_if.yul | 4 ++-- .../ssaAndBack/single_assign_switch.yul | 4 ++-- .../ssaAndBack/ssaReverse.yul | 4 ++-- .../yulOptimizerTests/ssaAndBack/two_vars.yul | 4 ++-- .../ssaPlusCleanup/control_structures.yul | 4 ++-- .../ssaPlusCleanup/multi_reassign.yul | 4 ++-- .../multi_reassign_with_use.yul | 4 ++-- .../ssaReverser/abi_example.yul | 4 ++-- .../ssaReverser/self_assign.yul | 4 ++-- .../yulOptimizerTests/ssaReverser/simple.yul | 4 ++-- .../ssaTransform/branches.yul | 4 ++-- .../ssaTransform/for_reassign_body.yul | 4 ++-- .../ssaTransform/for_reassign_init.yul | 4 ++-- .../ssaTransform/for_reassign_post.yul | 4 ++-- .../ssaTransform/for_simple.yul | 4 ++-- .../ssaTransform/function.yul | 4 ++-- .../ssaTransform/multi_assign.yul | 4 ++-- .../ssaTransform/multi_decl.yul | 4 ++-- .../yulOptimizerTests/ssaTransform/nested.yul | 4 ++-- .../ssaTransform/nested_reassign.yul | 4 ++-- .../ssaTransform/notransform.yul | 4 ++-- .../yulOptimizerTests/ssaTransform/simple.yul | 4 ++-- .../yulOptimizerTests/ssaTransform/switch.yul | 4 ++-- .../ssaTransform/switch_reassign.yul | 4 ++-- .../yulOptimizerTests/ssaTransform/typed.yul | 3 ++- .../ssaTransform/typed_for.yul | 3 ++- .../ssaTransform/typed_switch.yul | 3 ++- .../yulOptimizerTests/ssaTransform/used.yul | 4 ++-- .../stackCompressor/inlineInBlock.yul | 4 ++-- .../stackCompressor/inlineInFunction.yul | 4 ++-- .../stackCompressor/noInline.yul | 4 ++-- .../stackCompressor/unusedPrunerWithMSize.yul | 4 ++-- .../bugfix_visit_after_change.yul | 4 ++-- ..._condition.sol => for_false_condition.yul} | 4 ++-- .../if_false_condition.yul | 4 ++-- .../if_multi_unassigned_condition.yul | 4 ++-- .../if_true_condition.yul | 4 ++-- .../if_unassigned_condition.yul | 4 ++-- .../structuralSimplifier/nested.yul | 4 ++-- .../structuralSimplifier/switch_inline.yul | 4 ++-- .../switch_inline_match_default.yul | 4 ++-- .../switch_inline_no_match.yul | 4 ++-- .../switch_inline_no_match_mixed.yul | 4 ++-- .../switch_no_remove_empty_case.yul | 4 ++-- .../unusedPruner/functions.yul | 4 ++-- .../unusedPruner/intermediate_assignment.yul | 4 ++-- .../intermediate_multi_assignment.yul | 4 ++-- .../yulOptimizerTests/unusedPruner/keccak.yul | 4 ++-- .../movable_user_defined_function.yul | 4 ++-- .../yulOptimizerTests/unusedPruner/msize.yul | 4 ++-- .../unusedPruner/multi_assign.yul | 4 ++-- .../unusedPruner/multi_assignments.yul | 4 ++-- .../unusedPruner/multi_declarations.yul | 4 ++-- .../unusedPruner/multi_declare.yul | 4 ++-- .../multi_partial_assignments.yul | 4 ++-- .../unusedPruner/no_msize.yul | 4 ++-- .../yulOptimizerTests/unusedPruner/pop.yul | 4 ++-- .../yulOptimizerTests/unusedPruner/smoke.yul | 4 ++-- .../unusedPruner/trivial.yul | 4 ++-- .../varDeclInitializer/ambiguous.yul | 4 ++-- .../varDeclInitializer/inside_func.yul | 4 ++-- .../varDeclInitializer/multi.yul | 4 ++-- .../varDeclInitializer/multi_assign.yul | 4 ++-- .../varDeclInitializer/simple.yul | 4 ++-- .../varDeclInitializer/typed.yul | 3 ++- .../varNameCleaner/builtins.yul | 4 ++-- .../varNameCleaner/function_names.yul | 4 ++-- .../varNameCleaner/function_parameters.yul | 4 ++-- .../varNameCleaner/function_scopes.yul | 4 ++-- .../varNameCleaner/instructions.yul | 4 ++-- .../varNameCleaner/name_stripping.yul | 4 ++-- .../varNameCleaner/reshuffling-inverse.yul | 4 ++-- .../varNameCleaner/reshuffling.yul | 4 ++-- .../wordSizeTransform/constant_assignment.yul | 4 ++-- .../wordSizeTransform/function_call.yul | 4 ++-- .../functional_instruction.yul | 4 ++-- .../wordSizeTransform/if.yul | 4 ++-- .../wordSizeTransform/or_bool_renamed.yul | 4 ++-- .../wordSizeTransform/switch_1.yul | 4 ++-- .../wordSizeTransform/switch_2.yul | 4 ++-- .../wordSizeTransform/switch_3.yul | 4 ++-- .../wordSizeTransform/switch_4.yul | 4 ++-- .../wordSizeTransform/switch_5.yul | 4 ++-- 410 files changed, 817 insertions(+), 798 deletions(-) rename test/libyul/yulOptimizerTests/structuralSimplifier/{for_false_condition.sol => for_false_condition.yul} (93%) diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 6ab4b181fa9b..9458174edb34 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -103,8 +103,6 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename): auto dialectName = m_reader.stringSetting("dialect", "evm"); m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); - m_step = m_reader.stringSetting("step", ""); - m_expectation = m_reader.simpleExpectations(); } @@ -352,21 +350,8 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line return TestResult::FatalError; } - m_obtainedResult = AsmPrinter{*m_dialect}(*m_ast) + "\n"; + m_obtainedResult = "step: " + m_optimizerStep + "\n\n" + AsmPrinter{ *m_dialect }(*m_ast) + "\n"; - if (m_optimizerStep != m_step) - { - string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << - _linePrefix << - "Invalid optimizer step. Given: \"" << - m_step << - "\", should be: \"" << - m_optimizerStep << - "\"." << - endl; - return TestResult::FatalError; - } if (m_expectation != m_obtainedResult) { string nextIndentLevel = _linePrefix + " "; @@ -385,13 +370,6 @@ void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix, printIndented(_stream, m_source, _linePrefix); } -void YulOptimizerTest::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool _formatted) -{ - m_step = m_optimizerStep; - m_reader.setSetting("step", m_step); - EVMVersionRestrictedTestCase::printUpdatedSettings(_stream, _linePrefix, _formatted); -} - void YulOptimizerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const { printIndented(_stream, m_obtainedResult, _linePrefix); diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 64e3cc83dfd7..99e239e3b90f 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -57,7 +57,6 @@ class YulOptimizerTest: public solidity::frontend::test::EVMVersionRestrictedTes TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override; - void printUpdatedSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) override; void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override; private: @@ -73,7 +72,6 @@ class YulOptimizerTest: public solidity::frontend::test::EVMVersionRestrictedTes std::string m_expectation; Dialect const* m_dialect = nullptr; - std::string m_step; std::set m_reservedIdentifiers; std::unique_ptr m_nameDispenser; std::unique_ptr m_context; diff --git a/test/libyul/yulOptimizerTests/blockFlattener/basic.yul b/test/libyul/yulOptimizerTests/blockFlattener/basic.yul index 8558737cfc52..e5761743679a 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/basic.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/basic.yul @@ -8,9 +8,9 @@ } let z := mload(2) } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let _1 := mload(0) // let f_a := mload(1) diff --git a/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul index dfb88a1785ef..a5be68a7cea4 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/for_stmt.yul @@ -3,9 +3,9 @@ a := add(a, 1) } } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } // { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul index ca5055ac9cb8..f31c5f979cc6 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/if_stmt.yul @@ -8,9 +8,9 @@ } let t := add(3, 9) } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // if add(mload(7), sload(mload(3))) // { diff --git a/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul b/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul index a397000e416a..d7fd4b45a423 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/many_nested_blocks.yul @@ -14,9 +14,9 @@ a := add(a, c) } } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let a := 3 // let b := 4 diff --git a/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul b/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul index f3243296b67d..0b2a8245de38 100644 --- a/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul +++ b/test/libyul/yulOptimizerTests/blockFlattener/switch_stmt.yul @@ -5,9 +5,9 @@ default { a := 3 { a := 4 } } a := 5 } -// ==== -// step: blockFlattener // ---- +// step: blockFlattener +// // { // let a := 1 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul index 07eca2709077..739ba78bffa8 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/called_from_non_function.yul @@ -5,9 +5,9 @@ function h() -> z { z := g() } a := h() } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { // let a // a := h() diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul index 0630fe35f27b..ac04f96a81c1 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_different_names.yul @@ -8,7 +8,7 @@ function d() -> w { w := c() } } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul index 9873c717fcff..02ac2317de94 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/nested_same_name.yul @@ -8,7 +8,7 @@ function y() -> x { x := z() } } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul b/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul index c0fe6834ad8e..4398bc29f4a8 100644 --- a/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul +++ b/test/libyul/yulOptimizerTests/circularReferencesPruner/trivial.yul @@ -2,7 +2,7 @@ function f() -> x { x := g() } function g() -> x { x := f() } } -// ==== -// step: circularReferencesPruner // ---- +// step: circularReferencesPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul index a077efcf1c1d..ac4ed1b0545e 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_for.yul @@ -6,9 +6,9 @@ } mstore(1, codesize()) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := 1 // let b := codesize() diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul index e664aa7812b6..8de646ae3547 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/branches_if.yul @@ -3,9 +3,9 @@ if b { b := 1 } let c := 1 } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let b := 1 // if b { b := b } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul index ab08c0dee173..3a51b6626dec 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/case2.yul @@ -23,9 +23,9 @@ p_1 := add(array, _22) } } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let _13 := 0x20 // let _14 := allocate(_13) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul index 89075e3bbb8a..d0e124f6b52e 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/clear_not_needed.yul @@ -7,9 +7,9 @@ a := 9 sstore(x, 3) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := calldataload(0) // let x := calldataload(0x20) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul index 957232a8f19f..1fd8f84f1fcf 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/function_scopes.yul @@ -23,9 +23,9 @@ let _11 := array_index_access(x, _10) mstore(_11, _9) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function allocate(size) -> p // { diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul index 4725a444eee0..2848ef3f10eb 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/loop.yul @@ -35,9 +35,9 @@ } sstore(_1, sum_50) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let _1 := 0 // let _33 := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul index 3b3e65dbd374..ac0fa0f52d05 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/movable_functions.yul @@ -7,9 +7,9 @@ let c := double_with_se(i) let d := double_with_se(i) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function double(x) -> y // { y := add(x, x) } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul index 42b4274ce65d..a9f5664eccd3 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr.yul @@ -2,9 +2,9 @@ let a := mload(1) let b := mload(1) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mload(1) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul index 6fee35665d3a..ed8916e63723 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/non_movable_instr2.yul @@ -2,9 +2,9 @@ let a := gas() let b := gas() } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := gas() // let b := gas() diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul index 4c1e0feebe57..0f723c6c18de 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/object_access.yul @@ -14,9 +14,9 @@ object "main" { } data "abc" "Hello, World!" } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let r := "abc" // let a := datasize("abc") diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul index 44d08679fa13..5e5b79696c8b 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/scopes.yul @@ -10,9 +10,9 @@ mstore(0, calldataload(0)) mstore(0, x) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := 10 // let x := 20 diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul index 2457b3b56ceb..ab0d0a1ea236 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { } diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul index 1fdc65d43c97..c64fc93f9833 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/trivial.yul @@ -2,9 +2,9 @@ let a := mul(1, codesize()) let b := mul(1, codesize()) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mul(1, codesize()) // let b := a diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul index 178b8c52366b..46bf80eb7bba 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_return.yul @@ -9,9 +9,9 @@ let b := 0 sstore(a, b) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // function f() -> x // { diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul index 0012af03717a..ab14e04250a0 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/unassigned_variables.yul @@ -5,9 +5,9 @@ let b mstore(sub(a, b), 7) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul index 9f1bda6651fd..52198a1732f3 100644 --- a/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul +++ b/test/libyul/yulOptimizerTests/commonSubexpressionEliminator/variable_for_variable.yul @@ -12,9 +12,9 @@ a := b mstore(2, a) } -// ==== -// step: commonSubexpressionEliminator // ---- +// step: commonSubexpressionEliminator +// // { // let a := mload(0) // let b := add(a, 7) diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul index f0b46072f14c..c7cc17fc8fd4 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type.yul @@ -6,8 +6,9 @@ } // ==== // dialect: yul -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y:bool := false // for { } true { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul index ab523246e33d..de92aad7aefa 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/add_correct_type_wasm.yul @@ -6,8 +6,9 @@ } // ==== // dialect: ewasm -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y:i32 := 0:i32 // for { } true { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul index 00c46fcdff93..d49ec0709e79 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_break.yul @@ -4,9 +4,9 @@ if y { break } } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul index 1e6b0828a971..9246c162b1f4 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_after_if_continue.yul @@ -4,9 +4,9 @@ if y { continue } } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul index e936287db59b..35ba33c6ec44 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_condition.yul @@ -7,9 +7,9 @@ x := 2 } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // let y := mload(0) diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul index c541590bd8bf..4207525c7e8d 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/clear_before_for_post.yul @@ -8,9 +8,9 @@ } sstore(0, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x // for { } x { sstore(1, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul index 101407783d7a..6aa3ba57d71b 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_if_break_is_not_last.yul @@ -7,9 +7,9 @@ sstore(10, x) } } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // for { } 1 { } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul index 86983b3162e0..ef262b2e6ead 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/no_opt_inside_if.yul @@ -3,9 +3,9 @@ if x { sstore(0, x) } sstore(1, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // if x { sstore(0, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul index ca8bbba871a2..0326a5c3ad97 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_after_terminating_if.yul @@ -3,9 +3,9 @@ if x { sstore(0, x) revert(0, 0) } sstore(1, x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := mload(0) // if x diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul index 1f4da9eea840..58a43c0d2481 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/opt_switch.yul @@ -7,9 +7,9 @@ pop(x) } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { // let x := calldataload(0) // switch x diff --git a/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul b/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul index f37bf3d016b2..17e4d03a2466 100644 --- a/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/conditionalSimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: conditionalSimplifier // ---- +// step: conditionalSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul index 01b3016107f5..a12f171c650a 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_break.yul @@ -5,9 +5,9 @@ y := 0 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul index d4014c2b058e..86f99e29873e 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_after_if_continue.yul @@ -5,9 +5,9 @@ y := 0 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let y := mload(0x20) // for { } and(y, 8) { pop(y) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul index de41539f0ca2..2ea623e7a9d3 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_condition.yul @@ -9,9 +9,9 @@ x := 2 } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // let y := mload(0) diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul index d84611352669..a7fadc4345a1 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/clear_before_for_post.yul @@ -7,9 +7,9 @@ } sstore(0, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x // for { } x { sstore(1, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul index a697c6d25be7..e5342b2a63ff 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_if_break_is_not_last.yul @@ -9,9 +9,9 @@ sstore(10, x) } } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // for { } 1 { } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul index 830ae064c1af..8c94644ce1ac 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/no_opt_inside_if.yul @@ -4,9 +4,9 @@ x := 0 sstore(1, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // if x { sstore(0, x) } diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul index 13ffc0bac5e0..d90e1fc4bd5b 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_after_terminating_if.yul @@ -4,9 +4,9 @@ x := 0 sstore(1, x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := mload(0) // if x diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul index 107b2923b9f0..361b0f77b26a 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/opt_switch.yul @@ -8,9 +8,9 @@ pop(x) } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { // let x := calldataload(0) // switch x diff --git a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul index cb88da72bbcd..176d7fd57b72 100644 --- a/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/conditionalUnsimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: conditionalUnsimplifier // ---- +// step: conditionalUnsimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul b/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul index 47b76fa7cf7a..a7c4126ac17c 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/difficult.yul @@ -4,9 +4,9 @@ let z := 0xffff0000ffff0000ffff0000ffff0000ff00ff00ffff0000ffff0000ffff0000 let w := 0xffffffff000000ffffef000001feff000067ffefff0000ff230002ffee00fff7 } -// ==== -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let x := 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00 // let y := 0x1100ff00ff00ff001100ff00ff001100ff00ff001100ff00ff001100ff001100 diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul b/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul index 6371638eba03..82dccdab41de 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/gaps.yul @@ -7,8 +7,9 @@ } // ==== // EVMVersion: >=constantinople -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let a := shl(172, 1) // let x := add(shl(248, 17), 0xffffffffffffffffffffffff23) diff --git a/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul b/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul index 0315fdab8143..af8a08886dd3 100644 --- a/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul +++ b/test/libyul/yulOptimizerTests/constantOptimiser/smallNumbers.yul @@ -4,9 +4,9 @@ for { let i := 0xff00 } lt(i, 2) { i := add(i, 3) } { } } -// ==== -// step: constantOptimiser // ---- +// step: constantOptimiser +// // { // let x := 8 // let y := 0xffff diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul index 87450d939d13..bf74a266ce4a 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_movable_condition.yul @@ -1,7 +1,7 @@ { let a := mload(0) if a {} } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let a := mload(0) // pop(a) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul index 737ff7bf1ae8..a204e6cec189 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/empty_if_non_movable_condition.yul @@ -1,5 +1,5 @@ { if mload(0) {} } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { pop(mload(0)) } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul index af7726df93f2..f0bf4b7c2a9e 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/remove_leave.yul @@ -3,9 +3,9 @@ function g() -> x { leave x := 7 } function h() -> x { if x { leave } } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // function f() -> x // { x := 7 } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul index 16e718d2e270..f52551ab454d 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_only_default.yul @@ -1,9 +1,9 @@ { switch mload(0) default { mstore(1, 2) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // pop(mload(0)) // { mstore(1, 2) } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul index fb2434ec7648..a04b87ae6b46 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_all.yul @@ -10,9 +10,9 @@ case 1 { } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // pop(add(y, 4)) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul index 4b4f2cc0c4e4..03879b263bd2 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_case.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } case 2 { y := 10 } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul index 57beacaa1964..223760723382 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_cases.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // if eq(1, calldataload(0)) { y := 9 } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul index c5c4e44a764c..7c6283a8fca0 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_remove_empty_default_case.yul @@ -5,9 +5,9 @@ case 2 { y := 10 } default { } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul index 4a3558b6526a..b314cd96de59 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/switch_to_if.yul @@ -1,9 +1,9 @@ { switch calldataload(0) case 2 { mstore(0, 0) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if eq(2, calldataload(0)) { mstore(0, 0) } // } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul index 6f7390d53367..8e48e2b6586f 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for.yul @@ -4,9 +4,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() { mstore(4, 5) } // } diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul index 2b6397269fee..7bf16956eab3 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested.yul @@ -8,9 +8,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(8, 9) } // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul index 5412a7952b29..806a8ebcbdad 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_nested_reversed.yul @@ -7,9 +7,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul index d6f7e5d18378..b8bf66163026 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert.yul @@ -5,9 +5,9 @@ revert(0, x) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // if calldatasize() // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul index 7ef55bc3c645..e8d034733ccd 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_revert_plus_break.yul @@ -6,9 +6,9 @@ revert(0, x) } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(1, 2) } // { diff --git a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul index 9d5ce5b84794..b92efd885229 100644 --- a/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul +++ b/test/libyul/yulOptimizerTests/controlFlowSimplifier/terminating_for_with_continue.yul @@ -5,9 +5,9 @@ break } } -// ==== -// step: controlFlowSimplifier // ---- +// step: controlFlowSimplifier +// // { // for { } calldatasize() { mstore(1, 2) } // { diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul index 3d350c43b39e..ef17a9708a7d 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/conditional_break.yul @@ -13,9 +13,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul index a0d751938e97..c7a3d98e1942 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_break.yul @@ -14,9 +14,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul index 61eae9ff2ed6..d6b9f9d23995 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_continue.yul @@ -14,9 +14,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul index 90dae56f0961..ce3c006727b3 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_leave.yul @@ -18,9 +18,9 @@ pop(f()) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // function f() -> x // { diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul index be13641c20cb..7e37d6d4b256 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_revert.yul @@ -15,9 +15,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // revert(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul index ee4227b6adee..ad157573685f 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/early_stop.yul @@ -15,9 +15,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // stop() diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul index 295a49504c53..f5e67f77f530 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/for_loop_init_decl.yul @@ -4,7 +4,7 @@ let i_1 := i_0 } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { stop() } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul index e1d0f30fe349..d5df28fb0973 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/function_after_revert.yul @@ -12,9 +12,9 @@ pop(add(1, 1)) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // fun() // revert(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul index b89c1e0b7fbd..088394ee0a3f 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/nested_revert.yul @@ -12,9 +12,9 @@ y := 10 } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let y := mload(0) // switch y diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul index c1003538d916..0e0a2b9c4f4d 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/no_removal.yul @@ -4,9 +4,9 @@ } mstore(0, 0) } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // { revert(0, 0) } // mstore(0, 0) diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul index 77e4303b6366..28425b6e18c0 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_break.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul index e3a0b7a2faea..e01ae0aed568 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_continue.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let a := 20 // for { } lt(a, 40) { a := add(a, 2) } diff --git a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul index 561ac2066f24..6999c39c0070 100644 --- a/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul +++ b/test/libyul/yulOptimizerTests/deadCodeEliminator/normal_stop.yul @@ -15,9 +15,9 @@ stop() } -// ==== -// step: deadCodeEliminator // ---- +// step: deadCodeEliminator +// // { // let b := 20 // let a := 20 diff --git a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul index c6b246ad0f4f..30f2e54794a0 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/for_statement.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul index 7a4cfe739a0e..f99c4e4476de 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/funtion_call.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c, d, f } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul index def0a2d3159b..6b6da1f189fa 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/if_statement.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul index b403dc095c44..d55afc4828b8 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/long_names.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/long_names.yul @@ -1,8 +1,9 @@ { { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } { let aanteuhdaoneudbrgkjiuaothduiathudaoeuh:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let aanteuhdaoneudbrgkjiuaothduiathudaoeuh diff --git a/test/libyul/yulOptimizerTests/disambiguator/smoke.yul b/test/libyul/yulOptimizerTests/disambiguator/smoke.yul index bfe22582a4fb..4ea58a6ef3cb 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/smoke.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: disambiguator // ---- +// step: disambiguator +// // { } diff --git a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul index 2ed2b9ad10f6..676416437795 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/smoke_yul.yul @@ -1,6 +1,7 @@ { } // ==== -// step: disambiguator // dialect: yul // ---- +// step: disambiguator +// // { } diff --git a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul index 0948b51b9470..16ee5353f79b 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/switch_statement.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a, b, c } // { diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables.yul b/test/libyul/yulOptimizerTests/disambiguator/variables.yul index 7b197f4205b4..65c93bbb9e88 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables.yul @@ -1,8 +1,9 @@ { { let a:u256 } { let a:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { let a } // { let a_1 } diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul index 9c72b82ff885..e2cf23756d56 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_clash.yul @@ -1,8 +1,9 @@ { { let a:u256 let a_1:u256 } { let a:u256 } } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul index fecb67a653df..a78af7dabcab 100644 --- a/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/disambiguator/variables_inside_functions.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: disambiguator // ---- +// step: disambiguator +// // { // { // let c diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul index e400e69ae4a7..5f561185d53e 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/multiple_complex.yul @@ -54,9 +54,9 @@ } } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // pop(f(1, 2, 3)) // pop(f(4, 5, 6)) diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul index 43629175bc52..69045f364141 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple.yul @@ -4,9 +4,9 @@ function f() { mstore(1, mload(0)) } function g() { mstore(1, mload(0)) } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // f() // f() diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul index 25ffa4017707..5967adc0e13c 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/simple_different_vars.yul @@ -4,9 +4,9 @@ function f() -> b { let a := mload(0) b := a } function g() -> a { let b := mload(0) a := b } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // pop(f()) // pop(f()) diff --git a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul index 9de10889bcde..490bfd07229b 100644 --- a/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul +++ b/test/libyul/yulOptimizerTests/equivalentFunctionCombiner/switch_case_order.yul @@ -4,9 +4,9 @@ function f(x) { switch x case 0 { mstore(0, 42) } case 1 { mstore(1, 42) } } function g(x) { switch x case 1 { mstore(1, 42) } case 0 { mstore(0, 42) } } } -// ==== -// step: equivalentFunctionCombiner // ---- +// step: equivalentFunctionCombiner +// // { // f(0) // f(1) diff --git a/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul b/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul index 37649a5724e7..12228009ab83 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/argument_duplication_heuristic.yul @@ -16,9 +16,9 @@ let y11:= ref1(y1) let y12:= ref3(y1) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function ref1(a) -> x // { x := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul b/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul index e95c4144c9ab..49237c2f640a 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/complex_with_evm.yul @@ -2,9 +2,9 @@ function f(a) -> x { x := add(a, a) } let y := f(calldatasize()) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := add(a, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul b/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul index d19082f2e7d3..42dc4f015f19 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/double_calls.yul @@ -3,9 +3,9 @@ function g(b, c) -> y { y := mul(mload(c), f(b)) } let y := g(calldatasize(), 7) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := add(a, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul b/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul index 923032af04c6..337751a7241f 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/double_recursive_calls.yul @@ -3,9 +3,9 @@ function g(b, s) -> y { y := f(b, f(s, s)) } let y := g(calldatasize(), 7) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a, r) -> x // { x := g(a, f(r, f(r, r))) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul b/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul index 1b2b702fe5e6..1698ac5ace27 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/no_inline_mload.yul @@ -3,9 +3,9 @@ function f(a) -> x { x := a } let y := f(mload(2)) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := a } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul b/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul index 5a116bcc34c8..48acca95c9da 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/no_move_with_sideeffects.yul @@ -6,9 +6,9 @@ function h() -> z { mstore(0, 4) z := mload(0) } let r := f(g(), h()) } -// ==== -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a, b) -> x // { x := add(b, a) } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul index 8c3cd28e3ee0..2b6dba24069f 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/simple.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f() -> x // { x := 2 } diff --git a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul index 5b73ed3fe025..0456654e3a82 100644 --- a/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul +++ b/test/libyul/yulOptimizerTests/expressionInliner/with_args.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: expressionInliner // ---- +// step: expressionInliner +// // { // function f(a) -> x // { x := a } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul b/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul index b2a204482b0f..045168cf1303 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/if_condition.yul @@ -10,9 +10,9 @@ let z := 3 let t := add(z, 9) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // if add(mload(7), sload(mload(3))) { let y := add(mload(3), 3) } // let t := add(3, 9) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul b/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul index 07982ca47949..461285ae246c 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/muli_wrong_order3.yul @@ -4,9 +4,9 @@ let x := mul(add(b, a), mload(2)) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(3) // let b := mload(6) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul index 9d9a139a2d1f..5fcd2c5bf252 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi.yul @@ -4,9 +4,9 @@ let x := mul(add(b, a), 2) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(mul(add(mload(6), mload(2)), 2), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul index 95a0eccb3d13..ed209e597dee 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_reference.yul @@ -3,9 +3,9 @@ let a := mload(2) let b := add(a, a) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // let b := add(a, a) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul index d8624dc14238..2837f70330a8 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order.yul @@ -7,9 +7,9 @@ let x := mul(a, add(2, b)) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // sstore(mul(a, add(2, mload(6))), 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul index 6296c3778f98..d69f9d8a5db0 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/multi_wrong_order2.yul @@ -4,9 +4,9 @@ let x := mul(add(a, b), 2) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // sstore(mul(add(a, mload(6)), 2), 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul index 02c4466a2e59..0e4f1916a258 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_across_blocks.yul @@ -11,9 +11,9 @@ } sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let x := calldataload(mload(2)) // sstore(x, 3) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul index 0cc4e8f6dffb..b453446ad2ce 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition1.yul @@ -1,9 +1,9 @@ { for { let b := mload(1) } b {} {} } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // for { let b := mload(1) } b { } // { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul index 1444769048f4..ab41999d50f3 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/no_replacement_in_loop_condition2.yul @@ -2,9 +2,9 @@ let a := mload(0) for { } a {} {} } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(0) // for { } a { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul b/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul index 12fa6ec51752..30bf46634868 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/only_assignment.yul @@ -5,9 +5,9 @@ x := add(a, 3) } } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // function f(a) -> x // { diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul b/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul index 97661414fc42..e327d0b33f67 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/reassignment.yul @@ -4,9 +4,9 @@ let b := mload(a) a := 4 } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let a := mload(2) // let b := mload(a) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul b/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul index 03d2a7aee463..5ec8a900ad5d 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/simple.yul @@ -3,9 +3,9 @@ let x := calldataload(a) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(calldataload(mload(2)), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul b/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul index 21bf67c890c7..812cb7e7c6ae 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/single_wrong_order.yul @@ -5,9 +5,9 @@ let d := add(b, c) sstore(d, 0) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // let b := sload(mload(3)) // sstore(add(b, mload(7)), 0) diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul b/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul index 7eb5f5285943..77f73f11266c 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul b/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul index e8e7877623f4..08f7bb9fb00b 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/switch_expression.yul @@ -14,9 +14,9 @@ let z := 3 let t := add(z, 9) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // switch add(mload(7), sload(mload(3))) // case 3 { let y := add(mload(3), 3) } diff --git a/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul b/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul index cf2b4a6155ab..d6c652e2c06a 100644 --- a/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul +++ b/test/libyul/yulOptimizerTests/expressionJoiner/triple.yul @@ -5,9 +5,9 @@ let x := mul(add(c, b), a) sstore(x, 3) } -// ==== -// step: expressionJoiner // ---- +// step: expressionJoiner +// // { // sstore(mul(add(mload(7), mload(6)), mload(2)), 3) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul index 809f6ff23e4a..7833193954af 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/assigned_vars_multi.yul @@ -3,9 +3,9 @@ let c, d := f() let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> x, z // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul index 94caf0782e79..d465600e3c6c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and.yul @@ -5,8 +5,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := shr(248, x) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul index 36c56834b79a..6649a86b57cb 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_2.yul @@ -10,8 +10,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul index f506c41bde21..4211b6afec10 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/combine_shift_and_and_3.yul @@ -8,8 +8,9 @@ } // ==== // EVMVersion: >byzantium -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := calldataload(0) // let a := and(shl(8, x), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul index 983a3b25117b..2f655efbae59 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constant_propagation.yul @@ -1,5 +1,5 @@ { let a := add(7, sub(mload(0), 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := mload(0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul index efbcf8712246..8bf04b987ff0 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/constants.yul @@ -1,5 +1,5 @@ { let a := add(1, mul(3, 4)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := 13 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul index cd74d73ad961..bbda84653601 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul @@ -3,9 +3,10 @@ let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0)) } // ==== -// step: expressionSimplifier // EVMVersion: >=constantinople // ---- +// step: expressionSimplifier +// // { // let a := create2(0, 0, 0x20, 0) // let b := create2(0, 0, 0x20, 0) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul index c7cc887dc6a6..44a8cabb0b83 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul @@ -2,9 +2,9 @@ let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff) let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := create(0, 0, 0x20) // let b := create(0, 0, 0x20) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul index e7b60d2df4db..38502d22cedb 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_complex.yul @@ -1,5 +1,5 @@ { let a := sub(calldataload(0), calldataload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := 0 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul index 2838eb1936b1..5f3d268ca561 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_negative.yul @@ -1,7 +1,7 @@ { let a := sub(calldataload(1), calldataload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := sub(calldataload(1), calldataload(0)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul index 554d080b2f56..d75ceb83148d 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/identity_rules_simple.yul @@ -2,9 +2,9 @@ let a := mload(0) let b := sub(a, a) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := mload(0) // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul index 0c92afe38926..73b6bfa545fd 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/including_function_calls.yul @@ -2,9 +2,9 @@ function f() -> a {} let b := add(7, sub(f(), 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul index 83906d67524d..b8b3ee35d84e 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/inside_for.yul @@ -2,9 +2,9 @@ let a := 10 for { } iszero(eq(a, 0)) { a := add(a, 1) } {} } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := 10 // for { } iszero(iszero(a)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul index 9ad8892431f1..fc75f131f942 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/invariant.yul @@ -2,9 +2,9 @@ let a := mload(sub(7, 7)) let b := sub(a, 0) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := mload(0) // let b := a diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul index d5e7c0ad483d..073db8d4e33c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/large_byte_access.yul @@ -5,9 +5,9 @@ // create cannot be removed. let d := byte(33, create(0, 0, 0x20)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := calldataload(0) // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul index 6d7b03035ca8..65a325d6c20b 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_1.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 8))) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // mstore(0, and(calldataload(0), 255)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul index d949b2f17f2e..d4e35af33925 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/mod_and_2.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 255))) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // mstore(0, and(calldataload(0), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul index 1430fd718da5..b7bc3e4f99c6 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_arguments.yul @@ -2,9 +2,9 @@ function f(a) -> b { } let c := sub(f(0), f(1)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f(a) -> b // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul index cc819fff8667..b43440128a01 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_different_names.yul @@ -3,9 +3,9 @@ function f2() -> b { } let c := sub(f1(), f2()) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f1() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul index fc43fa78807e..c0fa43e2c7e5 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_function_call_equality_not_movable.yul @@ -3,9 +3,9 @@ function f() -> a { } let b := sub(f(), f()) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul index cee563173d27..d153ae724337 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/not_applied_removes_non_constant_and_not_movable.yul @@ -3,9 +3,9 @@ { let a := div(keccak256(0, 0), 0) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := div(keccak256(0, 0), 0) // } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul index 8178c6d03705..fbc5befd0431 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reassign.yul @@ -3,9 +3,9 @@ x := 0 mstore(0, add(7, x)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let x := mload(0) // x := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul index cb5303eaff7d..b81ae96197a5 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/remove_redundant_shift_masking.yul @@ -6,8 +6,9 @@ } // ==== // EVMVersion: >=constantinople -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := shr(248, calldataload(0)) // let b := shr(248, calldataload(0)) diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul index 8d69bcc8d7bd..550c7becb16c 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/replace_too_large_shift.yul @@ -6,8 +6,9 @@ } // ==== // EVMVersion: >=constantinople -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let a := 0 // let b := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul index 8586396c452c..c1c0093ef4db 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/return_vars_zero.yul @@ -4,9 +4,9 @@ let y := add(d, add(c, 7)) } } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // function f() -> c, d // { let y := 7 } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul index 1d398f833ac5..9ca956c103d2 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/reversed.yul @@ -1,7 +1,7 @@ { let a := add(0, mload(0)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { let a := mload(0) } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul index 7e181a097786..14d65c4e9267 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/side_effects_in_for_condition.yul @@ -4,9 +4,10 @@ } } // ==== -// step: expressionSimplifier // EVMVersion: >byzantium // ---- +// step: expressionSimplifier +// // { // for { } div(create(0, 1, 0), shl(msize(), 1)) { } // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul index 7562dfb47e51..30a2f5e901db 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul index e5db5ff76b9a..e88877365a9e 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigend_vars_multi.yul @@ -3,9 +3,9 @@ let c, d let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let c, d // let y := 7 diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul index f8480a32734c..d66d4efb2ce0 100644 --- a/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/unassigned_vars.yul @@ -4,9 +4,9 @@ let d let y := add(d, add(c, 7)) } -// ==== -// step: expressionSimplifier // ---- +// step: expressionSimplifier +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul b/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul index 2eb72c1125c2..d56a5285e519 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/control_flow.yul @@ -7,9 +7,9 @@ } } } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 0 // let x := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul b/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul index bb73118ec98a..294cac14ab19 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/inside_function.yul @@ -5,9 +5,9 @@ } sstore(x, f(mload(2), mload(2))) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 3 // let _2 := 7 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul b/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul index 9699918718de..60492e027233 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/object_access.yul @@ -9,9 +9,9 @@ object "main" { } data "abc" "Hello, World!" } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let x := dataoffset("abc") // let y := datasize("abc") diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul b/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul index c47eebe7b490..c5f979bf1a54 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { } diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul b/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul index 3608cab4fc4c..3664a7e26474 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/switch.yul @@ -5,9 +5,9 @@ default { mstore(0, mload(3)) } x := add(mload(3), 4) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let x := 8 // let _1 := 0 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul b/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul index 3d48eed79a16..a70827b93048 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/trivial.yul @@ -1,9 +1,9 @@ { mstore(add(calldataload(2), mload(3)), 8) } -// ==== -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // let _1 := 8 // let _2 := 3 diff --git a/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul b/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul index 37f40f5e68e4..4bae497d6392 100644 --- a/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul +++ b/test/libyul/yulOptimizerTests/expressionSplitter/typed.yul @@ -11,8 +11,9 @@ } // ==== // dialect: ewasm -// step: expressionSplitter // ---- +// step: expressionSplitter +// // { // function fun(x:i32, y) -> t:i32, z:i32 // { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul index 95e171475f2e..031507a38026 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/cond_types.yul @@ -6,9 +6,9 @@ for { } a { } { } for { } add(a, a) { } { } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let a := 1 // for { } 42 { } diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul index 6f1ad5458a5b..41c9e4234b77 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/empty_body.yul @@ -1,9 +1,9 @@ { for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } { } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // for { let a := 1 } true { a := add(a, 1) } // { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul index 292284a65c91..acbe3e456918 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/nested.yul @@ -13,9 +13,9 @@ mstore(b,b) } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let random := 42 // for { diff --git a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul index f470264627b1..bbe7823072dc 100644 --- a/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul +++ b/test/libyul/yulOptimizerTests/forLoopConditionIntoBody/simple.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopConditionIntoBody // ---- +// step: forLoopConditionIntoBody +// // { // let random := 42 // for { let a := 1 } true { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul index 951a5fbe6f3e..6304c4de57a3 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul @@ -5,9 +5,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul index 9fa5fd37e764..38a00f752860 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let a := 1 // for { } iszero(eq(a, 10)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul index c751f4483208..331d9cdde435 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/nested.yul @@ -13,9 +13,9 @@ mstore(b,b) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul index c8db1e5aa1ad..0dad899616d5 100644 --- a/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul @@ -4,9 +4,9 @@ a := add(a, 1) } } -// ==== -// step: forLoopInitRewriter // ---- +// step: forLoopInitRewriter +// // { // let random := 42 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul index b3ec1bbe8b16..259e4aeda4c6 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/double_inline.yul @@ -4,9 +4,9 @@ let b3, c3 := f(a1) let b4, c4 := f(c3) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_2 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul index fd9d893ae31e..39c3bb2950c7 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/inside_condition.yul @@ -8,9 +8,9 @@ r := add(a, calldatasize()) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul index a088e1681905..151b7596ca43 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_multi_use.yul @@ -15,9 +15,9 @@ // This should be inlined because it is a constant as well (zero) let s := f(a3) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_1 := mload(2) diff --git a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul index b8c05b72c416..4bcfe6f19465 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/large_function_single_use.yul @@ -10,9 +10,9 @@ // Single-use functions are always inlined. let r := f(mload(1)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_6 := mload(1) diff --git a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul index 8e9c2019d325..b2162c520ec9 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/long_names.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/long_names.yul @@ -7,9 +7,9 @@ mstore(0, verylongfunctionname(verylongvariablename2)) mstore(1, verylongvariablename2) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let verylongvariablename2_1 := 3 diff --git a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul index f40563602cf7..7bc959ec8f58 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/move_up_rightwards_argument.yul @@ -5,9 +5,9 @@ } let y := add(mload(1), add(f(mload(2), mload(3), mload(4)), mload(5))) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(5) diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul index 2f8a85842505..56cac2704e64 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun.yul @@ -3,9 +3,9 @@ function g(b, c) -> y { y := mul(mload(c), f(b)) } let y := g(f(3), 7) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _1 := 7 diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul index 46980522df33..98c8e301065f 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_fun_callback.yul @@ -22,9 +22,9 @@ f(100) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let x_8 := 100 diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul index 7d90e011830f..21369f10b683 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_return.yul @@ -6,9 +6,9 @@ let r, s := f(mload(0)) mstore(r, s) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul b/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul index f9f01a193c0b..143ae35b27b8 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/multi_return_typed.yul @@ -6,8 +6,9 @@ } // ==== // dialect: evmTyped -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(3) diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul index 4a7837ca2e0c..c1ce89bcfe16 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_function.yul @@ -9,9 +9,9 @@ x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // function f(a) -> b // { b := sload(mload(a)) } diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul index 337612d37735..10ccc2a3794f 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_into_big_global_context.yul @@ -7,9 +7,9 @@ // the global context gets too big. let x := f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(f(2))))))))))))))))))) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_20 := 2 diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul b/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul index 552ce9a821a4..a22025c4b385 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_inline_leave.yul @@ -4,9 +4,9 @@ let a1 := calldataload(0) f(a1) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_2 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/no_return.yul b/test/libyul/yulOptimizerTests/fullInliner/no_return.yul index c45e7a3c7129..2897b5151d08 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/no_return.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/no_return.yul @@ -4,9 +4,9 @@ } f(mload(0)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul index 94282bf5cc74..5678a13fd9a1 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/not_inside_for.yul @@ -9,9 +9,9 @@ r := a } } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let a_3 := 0 diff --git a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul index 373416925bca..c46505c79a17 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/pop_result.yul @@ -8,9 +8,9 @@ } pop(add(f(7), 2)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _1 := 2 diff --git a/test/libyul/yulOptimizerTests/fullInliner/recursion.yul b/test/libyul/yulOptimizerTests/fullInliner/recursion.yul index 82632a9e7173..375327e652f9 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/recursion.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/recursion.yul @@ -4,9 +4,9 @@ } f(mload(0)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { f(mload(0)) } // function f(a) diff --git a/test/libyul/yulOptimizerTests/fullInliner/simple.yul b/test/libyul/yulOptimizerTests/fullInliner/simple.yul index af6fa8283954..2c9d979b5832 100644 --- a/test/libyul/yulOptimizerTests/fullInliner/simple.yul +++ b/test/libyul/yulOptimizerTests/fullInliner/simple.yul @@ -5,9 +5,9 @@ } let y := add(f(sload(mload(2))), mload(7)) } -// ==== -// step: fullInliner // ---- +// step: fullInliner +// // { // { // let _2 := mload(7) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul b/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul index 4c7fa2692135..968ec47673f7 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/constant_propagation.yul @@ -2,9 +2,9 @@ let a := add(7, sub(mload(0), 7)) mstore(a, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _2 := 0 // mstore(mload(_2), _2) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/constants.yul b/test/libyul/yulOptimizerTests/fullSimplify/constants.yul index 2ea5ea442c94..0b31d361f922 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/constants.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/constants.yul @@ -2,7 +2,7 @@ let a := add(1, mul(3, 4)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 13) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul index df7712b7a0bc..452ceaae6ff8 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_complex.yul @@ -2,7 +2,7 @@ let a := sub(calldataload(0), calldataload(0)) mstore(a, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul index bc7bf5b5a594..8c5e4e5dfca5 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_negative.yul @@ -2,9 +2,9 @@ let a := sub(calldataload(1), calldataload(0)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // mstore(_1, sub(calldataload(1), calldataload(_1))) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul index 1e9de7755c72..e8efb735c08a 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/identity_rules_simple.yul @@ -2,7 +2,7 @@ let a := mload(0) mstore(0, sub(a, a)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul b/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul index d75e681a4af7..73bd6c3639f9 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/including_function_calls.yul @@ -3,9 +3,9 @@ let b := add(7, sub(f(), 7)) mstore(b, 0) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f() -> a // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul b/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul index 339e744d748d..9d4e52dc1b3a 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/inside_for.yul @@ -3,9 +3,9 @@ let a := 10 for { } iszero(eq(a, sub(x, calldataload(3)))) { a := add(a, 1) } {} } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let a := 10 // for { } iszero(iszero(a)) { a := add(a, 1) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul b/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul index 453f74e33c85..687491818679 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/invariant.yul @@ -7,9 +7,9 @@ // run of CSE afterwards. mstore(b, eq(calldataload(0), a)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let a := calldataload(0) // let _4 := 0 diff --git a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul index 59dbf172b0f5..1e448c9a4f28 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_1.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 8))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _4 := 0 // mstore(_4, and(calldataload(_4), 255)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul index 41254b818e55..0756c1841d57 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/mod_and_2.yul @@ -1,9 +1,9 @@ { mstore(0, mod(calldataload(0), exp(2, 255))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _4 := 0 // mstore(_4, and(calldataload(_4), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul index 5038a6fa9920..8dd271d9fe04 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_arguments.yul @@ -2,9 +2,9 @@ function f(a) -> b { } mstore(0, sub(f(0), f(1))) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f(a) -> b // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul index 72ebadd20e78..0b17b1e4aff8 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_different_names.yul @@ -4,9 +4,9 @@ let c := sub(f1(), f2()) mstore(0, c) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f1() -> a // { } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul index 11de59aba47e..3133c69cab2c 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_function_call_equality_not_movable.yul @@ -4,9 +4,9 @@ let b := sub(f(), f()) mstore(0, b) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // function f() -> a // { mstore(1, 2) } diff --git a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul index 9f916198c6ce..05fc9447d683 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/not_applied_removes_non_constant_and_not_movable.yul @@ -3,9 +3,9 @@ let a := div(create(0, 0, 0), 0) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // pop(create(_1, _1, _1)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/operations.yul b/test/libyul/yulOptimizerTests/fullSimplify/operations.yul index 811f867805f6..93b424233079 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/operations.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/operations.yul @@ -19,9 +19,9 @@ mstore(17, or(x, not(x))) mstore(18, or(not(x), x)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // mstore(1, 0) // mstore(2, 0) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul b/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul index fceec7ecf89b..5fe6324959bd 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/reversed.yul @@ -2,9 +2,9 @@ let a := add(0, mload(0)) mstore(0, a) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // let _1 := 0 // mstore(_1, mload(_1)) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul b/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul index 13d4997dde64..9ebdf012894d 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/signextend.yul @@ -4,9 +4,9 @@ let y := 255 mstore(1, signextend(0, y)) } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { // mstore(0, 7) // mstore(1, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) diff --git a/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul b/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul index 7ff4c60c3e6d..15ff14a845e9 100644 --- a/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul +++ b/test/libyul/yulOptimizerTests/fullSimplify/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: fullSimplify // ---- +// step: fullSimplify +// // { } diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul index 384a47d893a3..2f400186aae6 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul @@ -1071,9 +1071,10 @@ } } // ==== -// step: fullSuite // EVMVersion: >=constantinople // ---- +// step: fullSuite +// // { // { // let _1 := mload(1) diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index 4557c1889487..5e6e0305dfa2 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -458,8 +458,9 @@ } // ==== // EVMVersion: >=constantinople -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := 0 diff --git a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul index 635da72d6053..1076f349a44e 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul @@ -228,9 +228,9 @@ mstore(0x00, keccak256(0x300, mul(n, 0x80))) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := 0x80 diff --git a/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul b/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul index a9cdb84e0c14..71ed36d9794d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/clear_after_if_continue.yul @@ -6,9 +6,9 @@ } if y { revert(0, 0) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let y := mload(0x20) diff --git a/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul b/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul index 314f2a363d8d..c5cdf81041b1 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/devcon_example.yul @@ -14,9 +14,9 @@ v := calldataload(add(data, mul(i, 0x20))) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul b/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul index f8fb81aa8f8e..3b30ac4f7f05 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/loopInvariantCodeMotion.yul @@ -17,9 +17,9 @@ v := add(v, calldataload(7)) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index c5ed25e2f010..4f1a6f35d06a 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -16,9 +16,9 @@ for { switch mul(1,2) case 2 { mstore(0x40, 0x20) } } sub(1,1) {} { mstore(0x80, 0x40) } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let p := mload(0x40) diff --git a/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul b/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul index 4efe81d899e3..f0ee054b9a01 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/no_move_loop_orig.yul @@ -7,9 +7,9 @@ } {} } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := iszero(caller()) diff --git a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul index fa1364297034..a0ac5c36d292 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/remove_redundant_assignments_in_switch.yul @@ -6,9 +6,9 @@ default { invalid() } mstore(1, 1) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // switch mload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul index bb350bf8faef..6e217ae4fbb4 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul @@ -9,7 +9,7 @@ mstore(sub(1,div(sub(x_9,1),sub(1,sub(x_9,1)))), 1) } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(1, 1) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul index c4a70b03ec1b..78af81f383f2 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul @@ -31,9 +31,9 @@ a,b := abi_decode_t_bytes_calldata_ptr(a,b) mstore(a,b) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let a, b := abi_decode_t_bytes_calldata_ptr(mload(0), mload(1)) diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul index 564ed9664cbb..4421dd3cdf20 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul @@ -9,9 +9,9 @@ } mstore(a, b) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let a := mload(0) diff --git a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul index 6a4e52652656..961abd72c48d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul @@ -20,9 +20,9 @@ sstore(0,0) sstore(3,1) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // let _1 := gt(not(pc()), 1) diff --git a/test/libyul/yulOptimizerTests/fullSuite/storage.yul b/test/libyul/yulOptimizerTests/fullSuite/storage.yul index 4daff379f296..7b3360847e18 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/storage.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/storage.yul @@ -3,9 +3,9 @@ sstore(4, 3) sstore(8, sload(4)) } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { // { // sstore(4, 5) diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul index 2e878e437909..65c7512d350d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul @@ -6,7 +6,7 @@ case 1 { y := 9 } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(9, 0) } } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul index 6710f1fee279..cff8bd755c1d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul @@ -7,7 +7,7 @@ default { y := 10 } } } -// ==== -// step: fullSuite // ---- +// step: fullSuite +// // { { mstore(10, 0) } } diff --git a/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul b/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul index 95117c38e728..b75efc54c408 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/already_grouped.yul @@ -4,9 +4,9 @@ } function f() -> y { y := 8 } } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let x := 2 } // function f() -> y diff --git a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul index f08de996b807..7bfbb340124f 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/empty_block.yul @@ -1,8 +1,9 @@ { let a:u256 { } function f() -> x:bool { let b:u256 := 4:u256 {} for {} f() {} {} } } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul b/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul index 4ad0c872dfcc..2e5380d2c220 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/grouped_but_not_ordered.yul @@ -4,9 +4,9 @@ let x := 2 } } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { { let x := 2 } } // function f() -> y diff --git a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul index 5fb398ad7516..1aedecf6a348 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/multi_fun_mixed.yul @@ -6,8 +6,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { // let a diff --git a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul index 455da2ef5bbe..9193da739c2b 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/nested_fun.yul @@ -10,8 +10,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let a } // function f() diff --git a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul index f7836b6c64fc..b007f1855a30 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/single_fun.yul @@ -3,8 +3,9 @@ } // ==== // dialect: yul -// step: functionGrouper // ---- +// step: functionGrouper +// // { // { let a } // function f() diff --git a/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul b/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul index 00895bf38c67..e292340f2985 100644 --- a/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul +++ b/test/libyul/yulOptimizerTests/functionGrouper/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: functionGrouper // ---- +// step: functionGrouper +// // { { } } diff --git a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul index 276fd4b0229e..bd66b3a2b1cd 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/empty_block.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function f() -> x:bool diff --git a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul index 4e9e9604f3e7..060fab314c96 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/multi_mixed.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // let c diff --git a/test/libyul/yulOptimizerTests/functionHoister/nested.yul b/test/libyul/yulOptimizerTests/functionHoister/nested.yul index 89ea5c0ffc23..05eb4803b0a6 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/nested.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/nested.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function g() diff --git a/test/libyul/yulOptimizerTests/functionHoister/single.yul b/test/libyul/yulOptimizerTests/functionHoister/single.yul index 6cc82e68ad09..205626b57f58 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/single.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/single.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: functionHoister // ---- +// step: functionHoister +// // { // let a // function f() diff --git a/test/libyul/yulOptimizerTests/functionHoister/smoke.yul b/test/libyul/yulOptimizerTests/functionHoister/smoke.yul index 27c9e84193e8..e0d43adbb394 100644 --- a/test/libyul/yulOptimizerTests/functionHoister/smoke.yul +++ b/test/libyul/yulOptimizerTests/functionHoister/smoke.yul @@ -1,6 +1,6 @@ { } -// ==== -// step: functionHoister // ---- +// step: functionHoister +// // { } diff --git a/test/libyul/yulOptimizerTests/loadResolver/loop.yul b/test/libyul/yulOptimizerTests/loadResolver/loop.yul index 4f7b27734176..3606891ee19e 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/loop.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/loop.yul @@ -4,9 +4,9 @@ x := add(x, 1)} {y := add(x, y) } } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 123213 // let _2 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul index a9487afa7fe2..77fc5aef0184 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul @@ -14,9 +14,9 @@ function g() {} } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 9 // let _2 := 2 diff --git a/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul b/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul index 17a8761d9866..199fb1f6c47a 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/memory_with_msize.yul @@ -5,9 +5,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := msize() // let _3 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul index 7f5dfb2f09f9..e9ced5f4c31f 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _3 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul index f7cfdd7c3a92..8ce9fba00cc4 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_known_write_with_distance.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _4 := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul index 4fc21bbf54ad..225e0f6272d5 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_unknown_write.yul @@ -7,9 +7,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // let _3 := 0 diff --git a/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul b/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul index ebe65992a8c3..b4b113e812e7 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/merge_with_rewrite.yul @@ -7,9 +7,9 @@ } sstore(0, mload(2)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 3 // let _2 := 2 diff --git a/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul b/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul index 9bb8261dd836..5e5c065535f4 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mload_in_function.yul @@ -6,9 +6,9 @@ foo(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function foo(x) // { diff --git a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul index 2de873942867..da910baceec1 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_body.yul @@ -11,9 +11,9 @@ funcWithLoop(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function userNot(x) -> y // { y := iszero(x) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul index 1e06cf8df3e3..efef507dc8d4 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/mstore_in_function_loop_init.yul @@ -11,9 +11,9 @@ funcWithLoop(42) sstore(0, mload(0)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function userNot(x) -> y // { y := iszero(x) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul b/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul index 7fb27c996c80..01e29b705e0a 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/re_store_memory.yul @@ -7,9 +7,9 @@ mstore(a, c) sstore(10, mload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul b/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul index aed91e002f9c..8c33e4f5dcbc 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/re_store_storage.yul @@ -7,9 +7,9 @@ sstore(a, c) mstore(32, sload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loadResolver/reassign.yul b/test/libyul/yulOptimizerTests/loadResolver/reassign.yul index fe7fccfe618f..4687422e92ac 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/reassign.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/reassign.yul @@ -4,9 +4,9 @@ a := calldataload(2) mstore(0, sload(a)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _1 := 0 // let a := calldataload(_1) diff --git a/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul b/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul index d2d0999fac6c..1b73cecb93d3 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/reassign_value_expression.yul @@ -14,9 +14,9 @@ a := 39 mstore(sload(a), 11) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul b/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul index ae23c1b8b08e..1aa05106c363 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_mstore_with_delta.yul @@ -9,9 +9,9 @@ mstore(b, 8) sstore(mload(a), mload(b)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store.yul index 67aa196f431f..f6f8250ce07e 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store.yul @@ -6,9 +6,9 @@ // if the two slots are different. mstore(0, sload(x)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // sstore(x, 7) diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul index b90b177b3ac6..a5cb459ad71a 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store_same_value.yul @@ -6,9 +6,9 @@ // written are 7. mstore(0, sload(x)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let _2 := 7 diff --git a/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul b/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul index a4154ce63ea4..c2e669b7f603 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/second_store_with_delta.yul @@ -9,9 +9,9 @@ sstore(b, 8) mstore(sload(a), sload(b)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let x := calldataload(1) // let a := add(x, 10) diff --git a/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul index b07883c3abad..ec9eec6c9e6e 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul @@ -8,9 +8,9 @@ stores() sstore(0, mload(2)) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // function stores() // { mstore(0, 1) } diff --git a/test/libyul/yulOptimizerTests/loadResolver/simple.yul b/test/libyul/yulOptimizerTests/loadResolver/simple.yul index a32a542418ab..a645f1692f1b 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/simple.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/simple.yul @@ -4,9 +4,9 @@ let q := sload(calldataload(0)) mstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // sstore(calldataload(0), _2) diff --git a/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul b/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul index a4c06ebdcea7..667abe053c2a 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/simple_memory.yul @@ -4,9 +4,9 @@ let q := mload(calldataload(0)) sstore(t, q) } -// ==== -// step: loadResolver // ---- +// step: loadResolver +// // { // let _2 := calldataload(10) // mstore(calldataload(0), _2) diff --git a/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul b/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul index 75307ad5df86..b24ab0170ce5 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/staticcall.yul @@ -10,9 +10,10 @@ mstore(0, sload(a)) } // ==== -// step: loadResolver // EVMVersion: >=byzantium // ---- +// step: loadResolver +// // { // let a := 0 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul index 82ea2bf78751..a1b58ceb2b7b 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/dependOnVarInLoop.yul @@ -7,9 +7,9 @@ mstore(a, not_inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul index c7e39cc70e99..19a85c813841 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/multi.yul @@ -9,9 +9,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul index 7f842bbdda34..19e681d6b6b4 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_loop.yul @@ -8,9 +8,9 @@ let q := g() } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // function f() -> x // { x := g() } diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul index 5f3eeb7ac7b5..2bb86008ef51 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/no_move_recursive_function.yul @@ -8,9 +8,9 @@ let q := g() } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // function f() -> x // { x := g() } diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul index 86cf1274e3d0..18feab0c1178 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/non-ssavar.yul @@ -7,9 +7,9 @@ mstore(a, not_inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul index 787c1756baac..15fe39ccd08e 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/nonMovable.yul @@ -6,9 +6,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 0 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul index a489b134babf..5fdabc7cb6fb 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/recursive.yul @@ -8,9 +8,9 @@ a := add(a, 1) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul index 970fec59f55e..b0527e2b646b 100644 --- a/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul +++ b/test/libyul/yulOptimizerTests/loopInvariantCodeMotion/simple.yul @@ -6,9 +6,9 @@ mstore(a, inv) } } -// ==== -// step: loopInvariantCodeMotion // ---- +// step: loopInvariantCodeMotion +// // { // let b := 1 // let a := 1 diff --git a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul index 741efd42b4e4..635e618d5f4c 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/empty_block.yul @@ -9,8 +9,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { diff --git a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul index 69fb0bef0cae..1d14937e7bde 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/multi_fun_mixed.yul @@ -7,8 +7,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { diff --git a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul index b97bb2f4d861..a888970e729e 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/nested_fun.yul @@ -8,8 +8,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { let a } diff --git a/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul index 1ab108f6b2e8..6b20d712cab1 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/single_fun.yul @@ -4,8 +4,9 @@ } // ==== // dialect: yul -// step: mainFunction // ---- +// step: mainFunction +// // { // function main() // { let a } diff --git a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul index 54ad2d843e7f..5bad02dfba15 100644 --- a/test/libyul/yulOptimizerTests/mainFunction/smoke.yul +++ b/test/libyul/yulOptimizerTests/mainFunction/smoke.yul @@ -1,8 +1,9 @@ {} // ==== -// step: mainFunction // dialect: yul // ---- +// step: mainFunction +// // { // function main() // { } diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul b/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul index 9c547d17ace5..54045ce379f1 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/funtion_call.yul @@ -6,9 +6,9 @@ function illegal5(illegal1, illegal2) -> illegal3 { illegal3 := add(illegal1, illegal2) } } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // let x := illegal4_1(1, 2) // function illegal4_1(illegal1_2, illegal2_3) -> illegal3_4 diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul b/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul index dae343217157..08b7bc43121d 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/variables.yul @@ -1,7 +1,7 @@ { { let illegal1 := 1 } { let illegal2 := 2 let illegal3, illegal4 } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // { let illegal1_1 := 1 } // { diff --git a/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul b/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul index 73228739aff4..472aa6a33e8f 100644 --- a/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul +++ b/test/libyul/yulOptimizerTests/nameDisplacer/variables_inside_functions.yul @@ -4,9 +4,9 @@ illegal3 := add(illegal1, illegal2) } } -// ==== -// step: nameDisplacer // ---- +// step: nameDisplacer +// // { // function f(illegal1_1, illegal2_2) -> illegal3_3 // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul index a7280364fbd3..314963368082 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for.yul @@ -7,9 +7,9 @@ a := 7 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a := 2 // a := 3 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul index 6b15425c9393..120b43ce81a5 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_branch.yul @@ -13,9 +13,9 @@ y := 8 mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // let y diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul index 647de0d24c34..1b795ad8c73a 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_break.yul @@ -12,9 +12,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul index 3ac614b67ed6..0ee9c551da7a 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue.yul @@ -15,9 +15,9 @@ } x := 3 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // for { } calldataload(0) { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul index ab7ba0df16c7..ee747ae5d040 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_2.yul @@ -12,9 +12,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul index 14faa2a752f5..b70f35d2bc27 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_continue_3.yul @@ -11,9 +11,9 @@ x := 3 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // for { } calldataload(0) { mstore(x, 0x42) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul index 87104647d8c5..f54b21af8b0b 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_decl_inside_break_continue.yul @@ -18,9 +18,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // for { } calldataload(0) { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul index 96571f435fb1..5edd71d58b38 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_noremove.yul @@ -25,9 +25,9 @@ } x := 13 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 2 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul index 6df6e33ef188..5b086bab8a4d 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_deep_simple.yul @@ -18,9 +18,9 @@ } } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // for { } 1 { } // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul index 5b0e70f8c150..ce084b1ce168 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_multi_break.yul @@ -34,9 +34,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul index 7e9518f89d19..a83f536668dc 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_nested.yul @@ -31,9 +31,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul index 3cf202582295..5d1e60738568 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_rerun.yul @@ -10,9 +10,9 @@ } x := 3 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul index eceba8c23bc0..5e88df9689ca 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/for_stmnts_after_break_continue.yul @@ -22,9 +22,9 @@ } mstore(x, 0x42) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x := 1 // let y := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul index 444f73265966..2a20ca8b69bb 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/function.yul @@ -11,9 +11,9 @@ } r := 2 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let r // function f(x, y) -> a, b diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul index 35b6c968f49f..2fab04a36fba 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if.yul @@ -9,9 +9,9 @@ // This enforces that none of the assignments above can be removed. mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul index 120c3e07b0d8..7585f848a2b2 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_overwrite_all_branches.yul @@ -10,9 +10,9 @@ d := 3 mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul index 9fadcbbe990e..637a32c02a2e 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/if_used_in_one_branch.yul @@ -10,9 +10,9 @@ d := 3 mstore(0, d) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let c // let d diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul index ef68155ad1d4..1caee198a10d 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/leave.yul @@ -20,9 +20,9 @@ t := 8 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // function f(a, b) -> x // { diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul index b4546aa558c6..f0845680f40c 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multi_assign.yul @@ -8,9 +8,9 @@ x := 3 y := 4 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // function f() -> a, b // { } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul index b094f25b7621..2b13ba3c36b8 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/multivar.yul @@ -5,9 +5,9 @@ b := a a := b } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a := 2 // a := 7 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul index a5e697555cdd..343c672dea0c 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/non_movable.yul @@ -3,9 +3,9 @@ a := 0 a := mload(0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a // a := mload(0) diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul index 8e75d82edb7c..035f66d3851e 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_break.yul @@ -11,9 +11,9 @@ mstore(0, x) } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let i := 0 // for { } lt(i, 2) { i := add(i, 1) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul index f5a29382b393..c4f3b3e43ff3 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/remove_continue.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let i := 0 // for { } lt(i, 2) { i := add(i, 1) } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul index 85c83bde859b..d3c6cb4a6da0 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/scopes.yul @@ -6,9 +6,9 @@ a := 2 } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let a // { let b } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul index 1fd827ed1fdb..12b9ae6b7140 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/simple.yul @@ -3,7 +3,7 @@ a := 1 a := 2 } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { let a } diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul index 547ae025b513..a39cdedd7029 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_all.yul @@ -7,9 +7,9 @@ default { x := 3 } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul index 7ab2036e1422..271bb4864c7a 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_in_one.yul @@ -6,9 +6,9 @@ case 0 { x := 2 } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul index 8dc43d7219f8..8d38dcc161d4 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_overwrite_use_combination.yul @@ -7,9 +7,9 @@ default { mstore(x, 1) } mstore(x, 0) } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // x := 1 diff --git a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul index f0b29f30114f..94de51b8893d 100644 --- a/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul +++ b/test/libyul/yulOptimizerTests/redundantAssignEliminator/switch_unused.yul @@ -5,9 +5,9 @@ switch calldataload(0) case 0 { mstore(0, 1) } } -// ==== -// step: redundantAssignEliminator // ---- +// step: redundantAssignEliminator +// // { // let x // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul index 520c87b92628..39a7f91b3317 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_for1.yul @@ -5,9 +5,9 @@ pop(a) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // pop(caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul index 4dd86f958347..59731d61782b 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_for2.yul @@ -7,9 +7,9 @@ } let x := a } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // pop(caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul index e664291f57ce..0a1e38fa6851 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_if.yul @@ -4,9 +4,9 @@ if b { pop(b) b := a } let c := b } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // let b := address() diff --git a/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul b/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul index e0aa0a385b4b..442d64654994 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/branches_switch.yul @@ -6,9 +6,9 @@ default { let x := a let y := b b := a } pop(add(a, b)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := 2 diff --git a/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul b/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul index 95733af88d41..c3f6ea6a2ac3 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/cheap_caller.yul @@ -6,9 +6,9 @@ mstore(add(a, a), mload(a)) sstore(a, sload(a)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := caller() // mstore(caller(), caller()) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul b/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul index 074100d899cc..7fc927a4a267 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/do_not_move_out_of_scope.yul @@ -7,9 +7,9 @@ } let b := x } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x // { diff --git a/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul b/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul index cc009509f225..6221f11606f4 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/do_remat_large_amounts_of_code_if_used_once.yul @@ -2,9 +2,9 @@ let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) let b := x } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) // let b := add(mul(calldataload(2), calldataload(4)), mul(2, calldatasize())) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul index e39b66b44abb..2721600038e2 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_break.yul @@ -13,9 +13,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul index 5a98c4c4d046..ed80715e9de5 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue.yul @@ -15,9 +15,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul index f01514cc5861..a5d8198b0628 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_2.yul @@ -20,9 +20,9 @@ } mstore(a, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul index ae04949d9b1b..1b9b3a84ae8d 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/for_continue_with_assignment_in_post.yul @@ -23,9 +23,9 @@ let x := b // does not rematerialize as b may be either origin() or callvalue() (btw: not caller()) let y := c // does not rematerialize as c may be either origin() or caller() } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul b/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul index 9f57a473961c..b00d50f264cc 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/large_constant.yul @@ -4,9 +4,9 @@ let a := 0xffffffffffffffffffffff mstore(a, a) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 0xffffffffffffffffffffff // mstore(a, a) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul b/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul index 6d388c19ead3..cc8d233981b6 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/large_constant_used_once.yul @@ -5,9 +5,9 @@ let a := 0xffffffffffffffffffffff mstore(0, a) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 0xffffffffffffffffffffff // mstore(0, 0xffffffffffffffffffffff) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul index 0d42afa97578..92aacb22973d 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/many_refs_small_cost_loop.yul @@ -12,9 +12,9 @@ let c := sdiv(x, 4) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul b/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul index ec79843b1e49..fb73227b71bd 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/medium_sized_constant.yul @@ -12,9 +12,9 @@ mstore(add(a, a), a) mstore(a, mload(a)) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let b := 2 // mstore(2, 2) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul index 8fdd1f002f21..4255445b31b4 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/no_remat_in_loop.yul @@ -18,9 +18,9 @@ } } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := origin() // let b := calldataload(0) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul index 1b59fd598af8..4cffa6a027a9 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_function.yul @@ -5,9 +5,9 @@ let c := a mstore(add(a, b), c) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // function f(x) -> y // { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul index 0fb8856049be..dc1d78c74a61 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/non_movable_instruction.yul @@ -4,9 +4,9 @@ let c := a mstore(add(a, b), c) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul b/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul index fe3cf5812684..ef6e12ab6ec2 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/reassign.yul @@ -6,9 +6,9 @@ let d := add(b, c) pop(a) pop(b) pop(c) pop(d) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := extcodesize(0) // let b := a diff --git a/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul b/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul index c10f9ddf2644..7af26af635c3 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/reassignment.yul @@ -5,9 +5,9 @@ let b := mload(a) pop(b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // pop(1) diff --git a/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul b/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul index e0452c4b80f6..e7c28202c5bf 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/smoke.yul @@ -1,5 +1,5 @@ {} -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul index 0eeb248a62cc..071c3c463912 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_loop.yul @@ -7,9 +7,9 @@ let y := add(x, 1) } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul index c95cf5454cef..3d4d65f0aebe 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/some_refs_small_cost_nested_loop.yul @@ -12,9 +12,9 @@ } } } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let x := 0xff // for { } lt(x, 0x100) { } diff --git a/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul b/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul index 35d4f0332a4a..04a797e20fb7 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/trivial.yul @@ -3,9 +3,9 @@ let b := a mstore(0, b) } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := 1 // let b := 1 diff --git a/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul b/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul index 076131cde2ec..bb5f029803fa 100644 --- a/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul +++ b/test/libyul/yulOptimizerTests/rematerialiser/update_asignment_remat.yul @@ -4,9 +4,9 @@ a := mul(a, 2) let b := a } -// ==== -// step: rematerialiser // ---- +// step: rematerialiser +// // { // let a := extcodesize(0) // a := mul(a, 2) diff --git a/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul index 7e60a54be77e..c8b22424ccd9 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/control_flow.yul @@ -6,9 +6,9 @@ } } } -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { // if mul(add(calldataload(0), 2), 3) // { diff --git a/test/libyul/yulOptimizerTests/splitJoin/functions.yul b/test/libyul/yulOptimizerTests/splitJoin/functions.yul index b4ad9ed8e778..e2f554dd0eb5 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/functions.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/functions.yul @@ -8,9 +8,9 @@ sstore(b, mul(b, 2)) } } -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { // let x := f(0) // function f(y) -> r diff --git a/test/libyul/yulOptimizerTests/splitJoin/smoke.yul b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul index d59bd5644de9..4aac31ddb680 100644 --- a/test/libyul/yulOptimizerTests/splitJoin/smoke.yul +++ b/test/libyul/yulOptimizerTests/splitJoin/smoke.yul @@ -1,5 +1,5 @@ {} -// ==== -// step: splitJoin // ---- +// step: splitJoin +// // { } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul b/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul index e4787540dc93..43b9ade6a055 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/for_loop.yul @@ -15,9 +15,9 @@ b := mload(a) } } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul index 0617c47e469b..2e818561c656 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign.yul @@ -6,9 +6,9 @@ a := mload(4) mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_5 := mload(4) // mstore(a_5, 0) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul index 73aee8516968..4815349d7d37 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_if.yul @@ -8,9 +8,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // if mload(1) { a := mload(3) } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul index b6eb0b6cf9cf..a0821ab3738c 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_if.yul @@ -9,9 +9,9 @@ } mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul index e747e85032b7..92a0ba8259ea 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_multi_var_switch.yul @@ -16,9 +16,9 @@ } mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // let b := mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul index 8265f500edae..63c4f8561eba 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/multi_assign_switch.yul @@ -13,9 +13,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // switch mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul b/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul index 15e56f4d6fe2..e2f130507a11 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/simple.yul @@ -3,9 +3,9 @@ a := mload(1) mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_2 := mload(1) // mstore(a_2, 0) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul index 0e777a5a5e80..e2516b45b971 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_if.yul @@ -6,9 +6,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // if mload(1) { a := mload(1) } diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul index aacad246a3f7..e6e0553c1811 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/single_assign_switch.yul @@ -9,9 +9,9 @@ } mstore(a, 0) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a := mload(0) // switch mload(1) diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul b/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul index fbb149c68c8b..da8d797b828a 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/ssaReverse.yul @@ -20,9 +20,9 @@ let a,b := abi_decode_t_bytes_calldata_ptr(mload(0),mload(1)) mstore(a,b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // function abi_decode_t_bytes_calldata_ptr(offset_12, end_13) -> arrayPos_14, length_15 // { diff --git a/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul b/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul index 1c246a754d16..6053bd9ac9a8 100644 --- a/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul +++ b/test/libyul/yulOptimizerTests/ssaAndBack/two_vars.yul @@ -7,9 +7,9 @@ b := mload(a) mstore(a, b) } -// ==== -// step: ssaAndBack // ---- +// step: ssaAndBack +// // { // let a_1 := mload(0) // let b_2 := mload(a_1) diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul index 28520d3c524e..104dc2822ea0 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/control_structures.yul @@ -10,9 +10,9 @@ } } } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // function copy(from, to) -> length // { diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul index 105970c3c24d..85e86e005efa 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign.yul @@ -5,9 +5,9 @@ a := 4 mstore(0, a) } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul index 6770fee2b5a2..75a045d05c93 100644 --- a/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul +++ b/test/libyul/yulOptimizerTests/ssaPlusCleanup/multi_reassign_with_use.yul @@ -5,9 +5,9 @@ a := mload(add(a, 4)) mstore(0, a) } -// ==== -// step: ssaPlusCleanup // ---- +// step: ssaPlusCleanup +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul b/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul index 18d404df0017..1c79777d259d 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/abi_example.yul @@ -19,9 +19,9 @@ } } } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { // function abi_decode_t_bytes_calldata_ptr(offset_12, end_13) -> arrayPos_14, length_15 // { diff --git a/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul b/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul index 48b9d39cfd15..1985f6c0888e 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/self_assign.yul @@ -2,7 +2,7 @@ let a := calldataload(0) a := a } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { let a := calldataload(0) } diff --git a/test/libyul/yulOptimizerTests/ssaReverser/simple.yul b/test/libyul/yulOptimizerTests/ssaReverser/simple.yul index 03dab25f91cd..be2cfe9d75d3 100644 --- a/test/libyul/yulOptimizerTests/ssaReverser/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaReverser/simple.yul @@ -4,9 +4,9 @@ a := a_1 mstore(a_1, 0) } -// ==== -// step: ssaReverser // ---- +// step: ssaReverser +// // { // let a := mload(1) // a := mload(0) diff --git a/test/libyul/yulOptimizerTests/ssaTransform/branches.yul b/test/libyul/yulOptimizerTests/ssaTransform/branches.yul index 76a45916046a..81f82451f33f 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/branches.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/branches.yul @@ -7,9 +7,9 @@ a := add(a, 1) mstore(a, 1) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul index 6901f9f17889..e1e1c13ba82f 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_body.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul index fcf1a4478a66..284bdbf3d8e4 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_init.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul index 217a043ad3b9..ac7e426abef5 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_reassign_post.yul @@ -6,9 +6,9 @@ } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul b/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul index cec4196330b3..77ac89a60d89 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/for_simple.yul @@ -13,9 +13,9 @@ } a := add(a, 8) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/function.yul b/test/libyul/yulOptimizerTests/ssaTransform/function.yul index b6e120f4049b..d41c18b04c60 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/function.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/function.yul @@ -6,9 +6,9 @@ a := add(a, d) } } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // function f(a, b) -> c, d // { diff --git a/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul b/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul index 4f1c44123a8a..ff4a0eb1de8a 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/multi_assign.yul @@ -7,9 +7,9 @@ b := mload(a) function f() -> x, y {} } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul index ea849ead97ce..06847711e465 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul @@ -6,9 +6,9 @@ sstore(a, b) function f(t, v) -> w, z {} } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let x_1, y_2 := f(1, 2) // let x := x_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/nested.yul b/test/libyul/yulOptimizerTests/ssaTransform/nested.yul index a48de00022b0..e075f06a2462 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/nested.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/nested.yul @@ -10,9 +10,9 @@ } a := add(b, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul b/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul index 7d2d7bc33e57..32d74f180be1 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/nested_reassign.yul @@ -11,9 +11,9 @@ // but not above because end of block mstore(0, x) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul b/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul index f42de9976228..b41998c59235 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/notransform.yul @@ -6,9 +6,9 @@ mstore(c, 0) c := add(a, b) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a := 1 // let b := add(a, 2) diff --git a/test/libyul/yulOptimizerTests/ssaTransform/simple.yul b/test/libyul/yulOptimizerTests/ssaTransform/simple.yul index d23d07d82e06..b52ec0c0504e 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/simple.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/simple.yul @@ -4,9 +4,9 @@ a := 3 a := 4 } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/switch.yul b/test/libyul/yulOptimizerTests/ssaTransform/switch.yul index 32d6b339bb22..8604be0e32ea 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/switch.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/switch.yul @@ -8,9 +8,9 @@ default { a := add(a, 8) } mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul b/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul index 775df55f46ac..3cf38ef38869 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/switch_reassign.yul @@ -6,9 +6,9 @@ // should still create an SSA variable for a mstore(0, a) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := mload(0) // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed.yul index f9d48a22730b..4b1aa164371c 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed.yul @@ -14,8 +14,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b_1:bool := true // let b:bool := b_1 diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul index 685c42a24ba9..596f56cb0369 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed_for.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b:bool := true // let c_1:bool := false diff --git a/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul b/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul index 7d61b1031da8..b87b5dbbc3e5 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/typed_switch.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let b:bool := true // let c_1:bool := false diff --git a/test/libyul/yulOptimizerTests/ssaTransform/used.yul b/test/libyul/yulOptimizerTests/ssaTransform/used.yul index c23bc6ee85dc..cbd0cdb25b0b 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/used.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/used.yul @@ -14,9 +14,9 @@ a := 4 mstore(a, 0) } -// ==== -// step: ssaTransform // ---- +// step: ssaTransform +// // { // let a_1 := 1 // let a := a_1 diff --git a/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul b/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul index 6c0ceef63a96..4ff05615717d 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/inlineInBlock.yul @@ -3,9 +3,9 @@ let y := calldataload(calldataload(9)) mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // mstore(calldataload(calldataload(9)), add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(calldataload(calldataload(9)), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) // } diff --git a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul index e74e788aaa57..f237ea8bbcbb 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/inlineInFunction.yul @@ -5,9 +5,9 @@ mstore(y, add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(add(y, 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)) } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let x := 8 // function f() diff --git a/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul b/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul index 39c46fb962e5..b5f3dd8725be 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/noInline.yul @@ -2,9 +2,9 @@ let x := 8 function f() { let y := 9 } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let x := 8 // function f() diff --git a/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul b/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul index f285d6b5e414..279c0d90145b 100644 --- a/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul +++ b/test/libyul/yulOptimizerTests/stackCompressor/unusedPrunerWithMSize.yul @@ -18,9 +18,9 @@ extcodecopy(1, msize(), 1, 1) } } -// ==== -// step: stackCompressor // ---- +// step: stackCompressor +// // { // let _17_72 := pc() // let _22_75 := pc() diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul index f180d50ad88b..94da17faa09f 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/bugfix_visit_after_change.yul @@ -6,7 +6,7 @@ x := 1 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x := 0 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul similarity index 93% rename from test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol rename to test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul index 0d352a3f9770..edca6b642ded 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.sol +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/for_false_condition.yul @@ -3,7 +3,7 @@ let b := a } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let a := 42 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul index ab08b18e86ff..3b7a391815c1 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_false_condition.yul @@ -1,5 +1,5 @@ { if 0 { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul index 836b4371c47e..bbed85bb011c 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_multi_unassigned_condition.yul @@ -3,7 +3,7 @@ if x { mstore(0, 0) } if y { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x, y } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul index 7d493efbccd8..bf1046fb269f 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_true_condition.yul @@ -1,5 +1,5 @@ { if 1 { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul index 4595fe89991a..bee5381c8627 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/if_unassigned_condition.yul @@ -2,7 +2,7 @@ let x if x { mstore(0, 0) } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let x } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul index 6783b6eee38a..44b2ecc61ea2 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/nested.yul @@ -1,5 +1,5 @@ { if 1 { if 1 { for { mstore(0, 0) } 0 {} { mstore(2, 3) } if 0 { mstore(1, 2) } } } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { mstore(0, 0) } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul index b80d4ea99991..faa0304df945 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline.yul @@ -4,9 +4,9 @@ case 0 { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // { y := 9 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul index 5e985d78e1a5..9238cb05763a 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_match_default.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { y := 10 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // { y := 10 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul index 584bbb73d460..9036db7092e1 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match.yul @@ -4,7 +4,7 @@ case 0 { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let y := 200 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul index 0dea1229264e..5eeae71ba265 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_inline_no_match_mixed.yul @@ -5,7 +5,7 @@ case "" { y := 8 } case 1 { y := 9 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { let y := 200 } diff --git a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul index 8629be3f6db4..f8cc0558aa2e 100644 --- a/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul +++ b/test/libyul/yulOptimizerTests/structuralSimplifier/switch_no_remove_empty_case.yul @@ -5,9 +5,9 @@ case 1 { y := 9 } default { y := 100 } } -// ==== -// step: structuralSimplifier // ---- +// step: structuralSimplifier +// // { // let y := 200 // switch calldataload(0) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/functions.yul b/test/libyul/yulOptimizerTests/unusedPruner/functions.yul index 80758f0822a1..cceace3bbb41 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/functions.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/functions.yul @@ -2,7 +2,7 @@ function f() { let a := 1 } function g() { f() } } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul index 1c1397061b42..32e96b9f3a20 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_assignment.yul @@ -3,9 +3,9 @@ a := 4 let b := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a := 1 // a := 4 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul index 2dd207fbfae2..bc05f09f8a6f 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/intermediate_multi_assignment.yul @@ -4,9 +4,9 @@ a := f() b := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a, b // function f() -> x diff --git a/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul b/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul index c6b93a648ad0..6ad93184a699 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/keccak.yul @@ -3,9 +3,9 @@ let b := keccak256(1, 1) sstore(0, msize()) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // pop(keccak256(1, 1)) // sstore(0, msize()) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul b/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul index 0d49d713bae1..09d366fb2931 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/movable_user_defined_function.yul @@ -7,7 +7,7 @@ } let x := f(g(2)) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/msize.yul b/test/libyul/yulOptimizerTests/unusedPruner/msize.yul index ae6beaa7508f..05ad7b743eee 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/msize.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/msize.yul @@ -3,9 +3,9 @@ let b := mload(10) sstore(0, msize()) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // pop(mload(10)) // sstore(0, msize()) diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul index 77e9306c92a4..47e114373be7 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_assign.yul @@ -4,9 +4,9 @@ function f() -> x, y { } a, b := f() } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let a // let b diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul index 01e573199e1e..86f175d69523 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_assignments.yul @@ -3,9 +3,9 @@ x := 1 y := 2 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let x, y // x := 1 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul index 76bd6a510fda..f727b0e93cb7 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_declarations.yul @@ -1,7 +1,7 @@ { let x, y } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul index b4f6a5a7e1c1..aa8ae0ad4bfc 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_declare.yul @@ -2,7 +2,7 @@ function f() -> x, y { } let a, b := f() } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul b/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul index 67d692f708f6..f54087a7d8c6 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/multi_partial_assignments.yul @@ -2,9 +2,9 @@ let x, y x := 1 } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { // let x, y // x := 1 diff --git a/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul b/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul index 8d40256eb496..7bfc4d788410 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/no_msize.yul @@ -3,7 +3,7 @@ let b := mload(10) sstore(0, 5) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { sstore(0, 5) } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/pop.yul b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul index 0890982151e2..66d16db1ed41 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/pop.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/pop.yul @@ -2,7 +2,7 @@ let a := 1 pop(a) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul b/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul index 9adf68be53dd..a2ac495a0405 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/smoke.yul @@ -1,5 +1,5 @@ { } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { } diff --git a/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul b/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul index b3a05d38f5ed..9de594351b6c 100644 --- a/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul +++ b/test/libyul/yulOptimizerTests/unusedPruner/trivial.yul @@ -3,7 +3,7 @@ let b := 1 mstore(0, 1) } -// ==== -// step: unusedPruner // ---- +// step: unusedPruner +// // { mstore(0, 1) } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul index 054d0b53cfa5..8d306ca16875 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul @@ -11,9 +11,9 @@ let b := 2 let x, y := f() } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul index f9510e32f63a..9a169b4354a1 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul @@ -8,9 +8,9 @@ let r r := 4 } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul index 4911a6bd21c8..4968e2b0400f 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul @@ -3,9 +3,9 @@ let a let b } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // let x := 0 // let y := 0 diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul index fac0eaa06bf9..f8c37f2c5016 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul @@ -7,9 +7,9 @@ let s := 3 let t } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // function f() -> x, y // { diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul index 62d21dd0fff4..2b7d1048f968 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul @@ -1,7 +1,7 @@ { let a } -// ==== -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { let a := 0 } diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul index 912246bea0db..069c68cab89e 100644 --- a/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul +++ b/test/libyul/yulOptimizerTests/varDeclInitializer/typed.yul @@ -8,8 +8,9 @@ } // ==== // dialect: evmTyped -// step: varDeclInitializer // ---- +// step: varDeclInitializer +// // { // let a1 := 0 // let a2:bool := false diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul b/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul index 694d21847d8c..b6ee0377f807 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/builtins.yul @@ -1,7 +1,7 @@ { let datasize_256 := 1 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { let datasize_1 := 1 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul index 629b5451eec2..ea4ca9ea221d 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_names.yul @@ -3,9 +3,9 @@ function f() { let f_1 } let f_10 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let f_1 // function f() diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul index 6f1d1817c6e2..1608dd6fb714 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_parameters.yul @@ -8,9 +8,9 @@ } let f_10 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let f_1 // function f(x) -> x_1, y diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul b/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul index 7dabb4d47e4d..c7d86ef98776 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/function_scopes.yul @@ -2,9 +2,9 @@ function f() { let x_1 := 0 } function g() { let x_2 := 0 } } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // function f() // { let x := 0 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul b/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul index acf71b1d9035..2d7dbeb4a0ac 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/instructions.yul @@ -1,7 +1,7 @@ { let mul_256 := 1 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { let mul_1 := 1 } diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul b/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul index 4104c9567799..cd32d8530f20 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/name_stripping.yul @@ -4,9 +4,9 @@ let a_4312 := 0xdeadbeef let _42 := 21718 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let a := 1 // let a_1 := 2 diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul index d96a7b0bec54..100e5ccc6b09 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling-inverse.yul @@ -4,9 +4,9 @@ let x_2 := 3 let x_1 := 4 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let x := 1 // let x_1 := 2 diff --git a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul index e1132ad8b3fc..d197d4ff352a 100644 --- a/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul +++ b/test/libyul/yulOptimizerTests/varNameCleaner/reshuffling.yul @@ -3,9 +3,9 @@ let x_2 := 2 let x_3 := 3 } -// ==== -// step: varNameCleaner // ---- +// step: varNameCleaner +// // { // let x := 1 // let x_1 := 2 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul index fadfbd61f011..10f8814a66ed 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/constant_assignment.yul @@ -3,9 +3,9 @@ val := 9876543219876543219876543219876543219876543219876543219876543219876543210 } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let val_0 := 196678011949 // let val_1 := 17592899865401375162 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul index d633e9500c45..3aef8c99ceea 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/function_call.yul @@ -12,9 +12,9 @@ } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // function swap(x_0, x_1, x_2, x_3, y_0, y_1, y_2, y_3) -> a_0, a_1, a_2, a_3, b_0, b_1, b_2, b_3 // { diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul index c1a99ef34016..5ac0bfc00a8d 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/functional_instruction.yul @@ -1,9 +1,9 @@ { let x := add(999999999999999999999999999999999999999999999999999999999999999, 77777777777777777777777777777777777777777777777777777777777777) } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 12390 // let _1_1 := 13186919961226471680 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul index 5bfef91b1254..b799760f839f 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/if.yul @@ -2,9 +2,9 @@ if calldataload(0) { sstore(0, 1) } if add(calldataload(0), calldataload(1)) { sstore(0, 2) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul index 016dd9bb80b1..803b289708f7 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/or_bool_renamed.yul @@ -2,9 +2,9 @@ let or_bool := 2 if or_bool { sstore(0, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let or_bool_3_0 := 0 // let or_bool_3_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul index 22cb7631e222..d40e2283fc12 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_1.yul @@ -5,9 +5,9 @@ case 2 { sstore(2, 1) } case 3 { sstore(3, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul index 12759e230039..a9612a392776 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_2.yul @@ -5,9 +5,9 @@ case 0x01000000000000000000000000000000000000020 { sstore(2, 1) } case 0x02000000000000000000000000000000000000020 { sstore(3, 1) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul index 617eebb6416a..403c579623ac 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_3.yul @@ -6,9 +6,9 @@ case 3 { sstore(3, 1) } default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul index 20f81d614a4d..d1f45a6231fd 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_4.yul @@ -6,9 +6,9 @@ case 0x02000000000000000000000000000000000000020 { sstore(3, 1) } default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 diff --git a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul index 2a42adefe333..a02243a25a10 100644 --- a/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul +++ b/test/libyul/yulOptimizerTests/wordSizeTransform/switch_5.yul @@ -2,9 +2,9 @@ switch calldataload(0) default { sstore(8, 9) } } -// ==== -// step: wordSizeTransform // ---- +// step: wordSizeTransform +// // { // let _1_0 := 0 // let _1_1 := 0 From f4d9f6772fbc2eb2ba697f7d5c02c1977f10f79a Mon Sep 17 00:00:00 2001 From: a3d4 Date: Thu, 19 Mar 2020 02:48:42 +0100 Subject: [PATCH 089/165] Unified use of settings. Removed a couple of unused functions. --- test/TestCase.cpp | 7 ++--- test/TestCase.h | 4 +-- test/TestCaseReader.cpp | 16 ++-------- test/TestCaseReader.h | 2 -- test/libsolidity/SemanticTest.cpp | 29 ++++++++++--------- .../semanticTests/viaYul/detect_mod_zero.sol | 2 +- .../viaYul/detect_mod_zero_signed.sol | 2 +- .../semanticTests/viaYul/keccak.sol | 2 +- .../semanticTests/viaYul/string_format.sol | 2 +- test/tools/isoltest.cpp | 4 +-- 10 files changed, 30 insertions(+), 40 deletions(-) diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 8b2afc7802f9..f952e40bdaa4 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -28,7 +28,7 @@ using namespace solidity; using namespace solidity::frontend; using namespace solidity::frontend::test; -void TestCase::printUpdatedSettings(ostream& _stream, const string& _linePrefix, const bool) +void TestCase::printSettings(ostream& _stream, const string& _linePrefix, const bool) { auto& settings = m_reader.settings(); if (settings.empty()) @@ -63,11 +63,10 @@ void TestCase::expect(string::iterator& _it, string::iterator _end, string::valu EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filename): TestCase(_filename) { - if (!m_reader.hasSetting("EVMVersion")) + string versionString = m_reader.stringSetting("EVMVersion", "any"); + if (versionString == "any") return; - string versionString = m_reader.stringSetting("EVMVersion", ""); - string comparator; size_t versionBegin = 0; for (auto character: versionString) diff --git a/test/TestCase.h b/test/TestCase.h index b4e7e3972fc4..0add6947b6b4 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -57,8 +57,8 @@ class TestCase /// If @arg _formatted is true, color-coding may be used to indicate /// error locations in the contract, if applicable. virtual void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false) const = 0; - /// Outputs the updated settings. - virtual void printUpdatedSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); + /// Outputs settings. + virtual void printSettings(std::ostream &_stream, std::string const &_linePrefix = "", bool const _formatted = false); /// Outputs test expectations to @arg _stream that match the actual results of the test. /// Each line of output is prefixed with @arg _linePrefix. virtual void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const = 0; diff --git a/test/TestCaseReader.cpp b/test/TestCaseReader.cpp index 2b7e201af9f0..0f49a640181b 100644 --- a/test/TestCaseReader.cpp +++ b/test/TestCaseReader.cpp @@ -49,14 +49,9 @@ string TestCaseReader::simpleExpectations() return parseSimpleExpectations(m_file); } -bool TestCaseReader::hasSetting(std::string const& _name) const -{ - return m_settings.count(_name) != 0; -} - bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue) { - if (!hasSetting(_name)) + if (m_settings.count(_name) == 0) return _defaultValue; m_unreadSettings.erase(_name); @@ -71,7 +66,7 @@ bool TestCaseReader::boolSetting(std::string const& _name, bool _defaultValue) size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultValue) { - if (!hasSetting(_name)) + if (m_settings.count(_name) == 0) return _defaultValue; m_unreadSettings.erase(_name); @@ -82,18 +77,13 @@ size_t TestCaseReader::sizetSetting(std::string const& _name, size_t _defaultVal string TestCaseReader::stringSetting(string const& _name, string const& _defaultValue) { - if (!hasSetting(_name)) + if (m_settings.count(_name) == 0) return _defaultValue; m_unreadSettings.erase(_name); return m_settings.at(_name); } -void TestCaseReader::setSetting(std::string const& _name, std::string const& _value) -{ - m_settings[_name] = _value; -} - void TestCaseReader::ensureAllSettingsRead() const { if (!m_unreadSettings.empty()) diff --git a/test/TestCaseReader.h b/test/TestCaseReader.h index 055b355b7cbc..5ab2268261d0 100644 --- a/test/TestCaseReader.h +++ b/test/TestCaseReader.h @@ -40,11 +40,9 @@ class TestCaseReader std::string simpleExpectations(); - bool hasSetting(std::string const& _name) const; bool boolSetting(std::string const& _name, bool _defaultValue); size_t sizetSetting(std::string const& _name, size_t _defaultValue); std::string stringSetting(std::string const& _name, std::string const& _defaultValue); - void setSetting(std::string const& _name, std::string const& _value); void ensureAllSettingsRead() const; diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 8b5112e1263b..ded01f8dd2a3 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -43,21 +43,24 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer m_source = m_reader.source(); m_lineOffset = m_reader.lineNumber(); - if (m_reader.hasSetting("compileViaYul")) + string choice = m_reader.stringSetting("compileViaYul", "false"); + if (choice == "also") { - string choice = m_reader.stringSetting("compileViaYul", ""); - if (choice == "also") - { - m_runWithYul = true; - m_runWithoutYul = true; - } - else - { - m_reader.setSetting("compileViaYul", "only"); - m_runWithYul = true; - m_runWithoutYul = false; - } + m_runWithYul = true; + m_runWithoutYul = true; + } + else if (choice == "true") + { + m_runWithYul = true; + m_runWithoutYul = false; + } + else if (choice == "false") + { + m_runWithYul = false; + m_runWithoutYul = true; } + else + BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + ".")); m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false); if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2) diff --git a/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol b/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol index d8defa17aedb..6340c71c385d 100644 --- a/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol +++ b/test/libsolidity/semanticTests/viaYul/detect_mod_zero.sol @@ -7,7 +7,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f(uint256,uint256): 10, 3 -> 1 // f(uint256,uint256): 10, 2 -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol b/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol index 9164bf06cf88..d93e18d063c5 100644 --- a/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol +++ b/test/libsolidity/semanticTests/viaYul/detect_mod_zero_signed.sol @@ -7,7 +7,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f(int256,int256): 10, 3 -> 1 // f(int256,int256): 10, 2 -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/keccak.sol b/test/libsolidity/semanticTests/viaYul/keccak.sol index 887faf9e43fe..58c37ebd6256 100644 --- a/test/libsolidity/semanticTests/viaYul/keccak.sol +++ b/test/libsolidity/semanticTests/viaYul/keccak.sol @@ -8,7 +8,7 @@ contract C { } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // keccak1() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107 // keccak2() -> 0x64e604787cbf194841e7b68d7cd28786f6c9a0a3ab9f8b0a0e87cb4387ab0107 diff --git a/test/libsolidity/semanticTests/viaYul/string_format.sol b/test/libsolidity/semanticTests/viaYul/string_format.sol index 2d9d71d7c3b0..98e4d1081949 100644 --- a/test/libsolidity/semanticTests/viaYul/string_format.sol +++ b/test/libsolidity/semanticTests/viaYul/string_format.sol @@ -5,7 +5,7 @@ contract C { function h() external pure returns (bytes4) { return 0xcafecafe; } } // ==== -// compileViaYul: only +// compileViaYul: true // ---- // f1() -> 0x20, 6, left(0x616263616263) // f2() -> 32, 47, 44048183223289766195424279195050628400112610419087780792899004030957505095210, 18165586057823232067963737336409268114628061002662705707816940456850361417728 diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index da85c9ed0012..ad689ffcf6c4 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -172,7 +172,7 @@ TestTool::Result TestTool::process() AnsiColorized(cout, formatted, {BOLD, CYAN}) << " Contract:" << endl; m_test->printSource(cout, " ", formatted); - m_test->printUpdatedSettings(cout, " ", formatted); + m_test->printSettings(cout, " ", formatted); cout << endl << outputMessages.str() << endl; return result == TestCase::TestResult::FatalError ? Result::Exception : Result::Failure; @@ -231,7 +231,7 @@ TestTool::Request TestTool::handleResponse(bool _exception) cout << endl; ofstream file(m_path.string(), ios::trunc); m_test->printSource(file); - m_test->printUpdatedSettings(file); + m_test->printSettings(file); file << "// ----" << endl; m_test->printUpdatedExpectations(file, "// "); return Request::Rerun; From f25157a5f843da572a209cd54cde8ea6d2c4401c Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 19 Mar 2020 14:40:38 +0100 Subject: [PATCH 090/165] Sort tests. --- .../{extracted => abiEncoderV1}/abi_decode_dynamic_array.sol | 0 .../{extracted => abiEncoderV1}/abi_decode_static_array.sol | 0 .../{extracted => abiEncoderV1}/abi_decode_static_array_v2.sol | 0 .../{extracted => abiEncoderV1}/abi_decode_trivial.sol | 0 .../semanticTests/{extracted => abiEncoderV1}/abi_decode_v2.sol | 0 .../{extracted => abiEncoderV1}/abi_decode_v2_calldata.sol | 0 .../{extracted => abiEncoderV1}/abi_decode_v2_storage.sol | 0 .../semanticTests/{extracted => abiEncoderV1}/abi_encode.sol | 0 .../semanticTests/{extracted => abiEncoderV1}/abi_encode_call.sol | 0 .../{extracted => abiEncoderV1}/abi_encode_decode_simple.sol | 0 .../{extracted => abiEncoderV1}/abi_encode_rational.sol | 0 .../semanticTests/{abiDecodeV1 => abiEncoderV1}/decode_slice.sol | 0 .../{abiDecodeV1 => abiEncoderV1}/dynamic_memory_copy.sol | 0 .../{extracted => abiEncoderV2}/abi_encode_empty_string_v2.sol | 0 .../{extracted => abiEncoderV2}/abi_encode_rational_v2.sol | 0 .../semanticTests/{extracted => abiEncoderV2}/abi_encode_v2.sol | 0 .../{extracted => accessor}/accessor_for_const_state_variable.sol | 0 .../{extracted => accessor}/accessor_for_state_variable.sol | 0 .../semanticTests/{extracted => arithmetics}/addmod_mulmod.sol | 0 .../{extracted => arithmetics}/addmod_mulmod_zero.sol | 0 .../semanticTests/{extracted => arithmetics}/divisiod_by_zero.sol | 0 .../{extracted => array}/array_copy_different_packing.sol | 0 .../{extracted => array}/array_copy_nested_array.sol | 0 .../{extracted => array}/array_copy_storage_abi_signed.sol | 0 .../array_copy_storage_storage_static_dynamic.sol | 0 .../array_copy_storage_storage_static_static.sol | 0 .../{extracted => array}/array_copy_target_leftover2.sol | 0 .../{extracted => array}/array_copy_target_simple.sol | 0 test/libsolidity/semanticTests/{extracted => array}/array_pop.sol | 0 .../{extracted => array}/array_pop_empty_exception.sol | 0 .../semanticTests/{extracted => array}/array_pop_isolated.sol | 0 .../libsolidity/semanticTests/{extracted => array}/array_push.sol | 0 .../{extracted => array}/array_push_packed_array.sol | 0 .../semanticTests/{extracted => array}/array_push_struct.sol | 0 .../semanticTests/{extracted => array}/byte_array_pop.sol | 0 .../{extracted => array}/byte_array_pop_copy_long.sol | 0 .../{extracted => array}/byte_array_pop_empty_exception.sol | 0 .../{extracted => array}/byte_array_pop_isolated.sol | 0 .../{extracted => array}/byte_array_pop_masking_long.sol | 0 .../semanticTests/{extracted => array}/byte_array_push.sol | 0 .../{extracted => array}/byte_array_push_transition.sol | 0 .../semanticTests/{extracted => array}/bytes_delete_element.sol | 0 .../semanticTests/{extracted => array}/bytes_length_member.sol | 0 .../semanticTests/{extracted => array}/calldata_array.sol | 0 .../{extracted => array}/calldata_array_dynamic_invalid.sol | 0 .../calldata_array_dynamic_invalid_static_middle.sol | 0 .../{extracted => array}/calldata_array_of_struct.sol | 0 .../{extracted => array}/calldata_array_of_struct_to_memory.sol | 0 .../{extracted => array}/calldata_dynamic_array_to_memory.sol | 0 .../{extracted => array}/constant_var_as_array_length.sol | 0 .../{extracted => array}/copy_function_storage_array.sol | 0 .../copy_internal_function_array_to_storage.sol | 0 .../create_dynamic_array_with_zero_length.sol | 0 .../semanticTests/{extracted => array}/create_memory_array.sol | 0 .../{extracted => array}/create_multiple_dynamic_arrays.sol | 0 .../{extracted => array}/delete_on_array_of_structs.sol | 0 .../{extracted => array}/dynamic_arrays_in_storage.sol | 0 .../{extracted => array}/dynamic_out_of_bounds_array_access.sol | 0 .../{extracted => array}/evm_exceptions_out_of_band_access.sol | 0 .../{extracted => array}/fixed_arrays_as_return_type.sol | 0 .../{extracted => array}/fixed_arrays_in_constructors.sol | 0 .../{extracted => array}/fixed_bytes_length_access.sol | 0 .../{extracted => array}/fixed_out_of_bounds_array_access.sol | 0 .../{extracted => array}/function_array_cross_calls.sol | 0 .../semanticTests/{extracted => array}/function_memory_array.sol | 0 .../{extracted => array}/inline_array_index_access_ints.sol | 0 .../{extracted => array}/inline_array_index_access_strings.sol | 0 .../semanticTests/{extracted => array}/inline_array_return.sol | 0 .../semanticTests/{extracted => array}/inline_array_singleton.sol | 0 .../inline_array_storage_to_memory_conversion_ints.sol | 0 .../inline_array_storage_to_memory_conversion_strings.sol | 0 .../{extracted => array}/inline_array_strings_from_document.sol | 0 .../{extracted => array}/memory_arrays_of_various_sizes.sol | 0 .../semanticTests/{extracted => array}/storage_array_ref.sol | 0 .../{extracted => builtinFunctions}/keccak256_empty.sol | 0 .../{extracted => builtinFunctions}/keccak256_with_bytes.sol | 0 .../{extracted => builtinFunctions}/ripemd160_empty.sol | 0 .../{extracted => builtinFunctions}/sha256_empty.sol | 0 .../{extracted => cleanup}/cleanup_address_types_shortening.sol | 0 .../{extracted => cleanup}/cleanup_bytes_types_shortening.sol | 0 .../{extracted => cleanup}/cleanup_in_compound_assign.sol | 0 .../semanticTests/{extracted => cleanup}/exp_cleanup.sol | 0 .../semanticTests/{extracted => cleanup}/exp_cleanup_direct.sol | 0 .../{extracted => cleanup}/exp_cleanup_nonzero_base.sol | 0 .../semanticTests/{extracted => constants}/constant_string.sol | 0 .../semanticTests/{extracted => constants}/constant_variables.sol | 0 .../{extracted => constants}/simple_constant_variables_test.sol | 0 .../{extracted => constructor}/base_constructor_arguments.sol | 0 .../{extracted => constructor}/constructor_arguments_external.sol | 0 .../{extracted => constructor}/constructor_arguments_internal.sol | 0 .../constructor_static_array_argument.sol | 0 .../evm_exceptions_in_constructor_call_fail.sol | 0 .../function_usage_in_constructor_arguments.sol | 0 .../functions_called_by_constructor.sol | 0 .../inline_member_init_inheritence_without_constructor.sol | 0 .../{extracted => constructor}/payable_constructor.sol | 0 .../{extracted => constructor}/store_function_in_constructor.sol | 0 .../store_internal_unused_function_in_constructor.sol | 0 .../store_internal_unused_library_function_in_constructor.sol | 0 .../{extracted => enums}/constructing_enums_from_ints.sol | 0 .../semanticTests/{extracted => enums}/enum_explicit_overflow.sol | 0 .../using_contract_enums_with_explicit_contract_name.sol | 0 .../semanticTests/{extracted => enums}/using_enums.sol | 0 .../semanticTests/{extracted => enums}/using_inherited_enum.sol | 0 .../{extracted => enums}/using_inherited_enum_excplicitly.sol | 0 .../call_function_returning_function.sol | 0 .../calling_nonexisting_contract_throws.sol | 0 .../calling_uninitialized_function.sol | 0 .../calling_uninitialized_function_in_detail.sol | 0 .../calling_uninitialized_function_through_array.sol | 0 .../{extracted => functionCall}/external_function.sol | 0 .../{extracted => functionCall}/external_public_override.sol | 0 .../{extracted => functionCall}/gas_and_value_basic.sol | 0 .../{extracted => functionCall}/gas_and_value_brace_syntax.sol | 0 .../semanticTests/{extracted => functionCall}/send_zero_ether.sol | 0 .../{extracted => functionTypes}/function_delete_stack.sol | 0 .../{extracted => functionTypes}/function_delete_storage.sol | 0 .../function_type_library_internal.sol | 0 .../{extracted => functionTypes}/mapping_of_functions.sol | 0 .../pass_function_types_externally.sol | 0 .../pass_function_types_internally.sol | 0 .../same_function_in_construction_and_runtime.sol | 0 .../same_function_in_construction_and_runtime_equality_check.sol | 0 .../semanticTests/{extracted => functionTypes}/store_function.sol | 0 .../uninitialized_internal_storage_function_call.sol | 0 .../inline_assembly_embedded_function_call.sol | 0 .../{extracted => inlineAssembly}/inline_assembly_for.sol | 0 .../{extracted => inlineAssembly}/inline_assembly_for2.sol | 0 .../inline_assembly_function_call.sol | 0 .../inline_assembly_function_call2.sol | 0 .../inline_assembly_function_call_assignment.sol | 0 .../{extracted => inlineAssembly}/inline_assembly_if.sol | 0 .../inline_assembly_in_modifiers.sol | 0 .../inline_assembly_memory_access.sol | 0 .../inline_assembly_read_and_write_stack.sol | 0 .../{extracted => inlineAssembly}/inline_assembly_recursion.sol | 0 .../inline_assembly_storage_access.sol | 0 .../inline_assembly_storage_access_inside_function.sol | 0 .../inline_assembly_storage_access_via_pointer.sol | 0 .../{extracted => inlineAssembly}/inline_assembly_switch.sol | 0 .../inline_assembly_write_to_stack.sol | 0 .../{extracted => inlineAssembly}/inlineasm_empty_let.sol | 0 .../{extracted => inlineAssembly}/keccak256_assembly.sol | 0 .../{extracted => intheritance}/access_base_storage.sol | 0 .../{extracted => intheritance}/address_overload_resolution.sol | 0 .../base_access_to_function_type_variables.sol | 0 .../derived_overload_base_function_direct.sol | 0 .../derived_overload_base_function_indirect.sol | 0 .../{extracted => intheritance}/explicit_base_class.sol | 0 .../{extracted => intheritance}/inherited_constant_state_var.sol | 0 .../{extracted => intheritance}/inherited_function.sol | 0 .../inherited_function_calldata_calldata_interface.sol | 0 .../inherited_function_calldata_memory.sol | 0 .../inherited_function_calldata_memory_interface.sol | 0 .../inherited_function_from_a_library.sol | 0 .../overloaded_function_call_resolve_to_first.sol | 0 .../overloaded_function_call_resolve_to_second.sol | 0 .../overloaded_function_call_with_if_else.sol | 0 .../pass_dynamic_arguments_to_the_base.sol | 0 .../pass_dynamic_arguments_to_the_base_base.sol | 0 .../pass_dynamic_arguments_to_the_base_base_with_gap.sol | 0 .../{extracted => intheritance}/super_in_constructor.sol | 0 .../semanticTests/{extracted => intheritance}/super_overload.sol | 0 .../{extracted => intheritance}/value_for_constructor.sol | 0 .../{extracted => libraries}/internal_library_function.sol | 0 .../{extracted => libraries}/internal_library_function_bound.sol | 0 .../internal_library_function_calling_private.sol | 0 .../internal_library_function_return_var_size.sol | 0 .../{extracted => libraries}/library_enum_as_an_expression.sol | 0 .../{extracted => libraries}/library_struct_as_an_expression.sol | 0 .../semanticTests/{extracted => literals}/scientific_notation.sol | 0 .../semanticTests/{extracted => modifiers}/break_in_modifier.sol | 0 .../{extracted => modifiers}/continue_in_modifier.sol | 0 .../semanticTests/{extracted => modifiers}/function_modifier.sol | 0 .../function_modifier_calling_functions_in_creation_context.sol | 0 .../function_modifier_for_constructor.sol | 0 .../{extracted => modifiers}/function_modifier_library.sol | 0 .../function_modifier_library_inheritance.sol | 0 .../function_modifier_local_variables.sol | 0 .../{extracted => modifiers}/function_modifier_loop.sol | 0 .../function_modifier_multi_invocation.sol | 0 .../function_modifier_multi_with_return.sol | 0 .../{extracted => modifiers}/function_modifier_multiple_times.sol | 0 .../function_modifier_multiple_times_local_vars.sol | 0 .../{extracted => modifiers}/function_modifier_overriding.sol | 0 .../{extracted => modifiers}/return_does_not_skip_modifier.sol | 0 .../semanticTests/{extracted => modifiers}/return_in_modifier.sol | 0 .../{extracted => modifiers}/stacked_return_with_modifiers.sol | 0 .../semanticTests/{extracted => reverts}/assert_require.sol | 0 .../{extracted => reverts}/invalid_enum_as_external_arg.sol | 0 .../{extracted => reverts}/invalid_enum_as_external_ret.sol | 0 .../{extracted => reverts}/invalid_enum_compared.sol | 0 .../semanticTests/{extracted => reverts}/invalid_enum_stored.sol | 0 .../semanticTests/{extracted => reverts}/invalid_instruction.sol | 0 test/libsolidity/semanticTests/{extracted => reverts}/revert.sol | 0 .../semanticTests/{extracted => reverts}/simple_throw.sol | 0 .../semanticTests/{extracted => shifts}/shift_cleanup.sol | 0 .../semanticTests/{extracted => shifts}/shift_cleanup_garbled.sol | 0 .../semanticTests/{extracted => shifts}/shift_constant_left.sol | 0 .../{extracted => shifts}/shift_constant_left_assignment.sol | 0 .../semanticTests/{extracted => shifts}/shift_constant_right.sol | 0 .../{extracted => shifts}/shift_constant_right_assignment.sol | 0 .../semanticTests/{extracted => shifts}/shift_left.sol | 0 .../semanticTests/{extracted => shifts}/shift_left_assignment.sol | 0 .../shift_left_assignment_different_type.sol | 0 .../{extracted => shifts}/shift_left_larger_type.sol | 0 .../semanticTests/{extracted => shifts}/shift_left_uint32.sol | 0 .../semanticTests/{extracted => shifts}/shift_left_uint8.sol | 0 .../{extracted => shifts}/shift_negative_constant_left.sol | 0 .../{extracted => shifts}/shift_negative_constant_right.sol | 0 .../semanticTests/{extracted => shifts}/shift_negative_rvalue.sol | 0 .../{extracted => shifts}/shift_negative_rvalue_assignment.sol | 0 .../semanticTests/{extracted => shifts}/shift_overflow.sol | 0 .../semanticTests/{extracted => shifts}/shift_right.sol | 0 .../{extracted => shifts}/shift_right_assignment.sol | 0 .../{extracted => shifts}/shift_right_assignment_signed.sol | 0 .../{extracted => shifts}/shift_right_negative_literal.sol | 0 .../{extracted => shifts}/shift_right_negative_lvalue.sol | 0 .../shift_right_negative_lvalue_assignment.sol | 0 .../{extracted => shifts}/shift_right_negative_lvalue_int16.sol | 0 .../{extracted => shifts}/shift_right_negative_lvalue_int32.sol | 0 .../{extracted => shifts}/shift_right_negative_lvalue_int8.sol | 0 .../semanticTests/{extracted => shifts}/shift_right_uint32.sol | 0 .../semanticTests/{extracted => shifts}/shift_right_uint8.sol | 0 test/libsolidity/semanticTests/{ => shifts}/shifts.sol | 0 .../semanticTests/{extracted => storage}/packed_functions.sol | 0 .../{extracted => storage}/packed_storage_overflow.sol | 0 .../{extracted => storage}/packed_storage_signed.sol | 0 .../{extracted => storage}/packed_storage_structs_bytes.sol | 0 .../{extracted => storage}/packed_storage_structs_enum.sol | 0 .../{extracted => storage}/packed_storage_structs_uint.sol | 0 .../{extracted => structs/calldata}/calldata_struct.sol | 0 .../{extracted => structs/calldata}/calldata_struct_and_ints.sol | 0 .../calldata}/calldata_struct_array_member.sol | 0 .../{extracted => structs/calldata}/calldata_struct_to_memory.sol | 0 .../{extracted => structs/calldata}/calldata_structs.sol | 0 .../{extracted => structs}/lone_struct_array_type.sol | 0 .../{extracted => structs}/memory_structs_as_function_args.sol | 0 .../{extracted => structs}/memory_structs_nested.sol | 0 .../{extracted => structs}/memory_structs_read_write.sol | 0 .../{extracted => structs}/memory_structs_with_mappings.sol | 0 .../semanticTests/{extracted => structs}/recursive_structs.sol | 0 .../{extracted => structs}/struct_assign_reference_to_struct.sol | 0 .../semanticTests/{extracted => structs}/struct_copy.sol | 0 .../{extracted => structs}/struct_copy_via_local.sol | 0 .../semanticTests/{extracted => structs}/struct_delete_member.sol | 0 .../{extracted => structs}/struct_delete_struct_in_mapping.sol | 0 .../{extracted => structs}/struct_named_constructor.sol | 0 .../assignment_to_const_var_involving_expression.sol | 0 test/libsolidity/semanticTests/{extracted => various}/balance.sol | 0 .../{extracted => various}/byte_optimization_bug.sol | 0 .../semanticTests/{extracted => various}/code_access_content.sol | 0 .../semanticTests/{extracted => various}/code_access_create.sol | 0 .../semanticTests/{extracted => various}/code_access_padding.sol | 0 .../{extracted => various}/contract_binary_dependencies.sol | 0 .../crazy_elementary_typenames_on_stack.sol | 0 .../semanticTests/{extracted => various}/cross_contract_types.sol | 0 .../semanticTests/{extracted => various}/decayed_tuple.sol | 0 .../{extracted => various}/destructuring_assignment.sol | 0 .../{extracted => various}/empty_name_return_parameter.sol | 0 .../{extracted => various}/external_types_in_calls.sol | 0 .../semanticTests/{extracted => various}/flipping_sign_tests.sol | 0 .../semanticTests/{extracted => various}/gasleft_decrease.sol | 0 .../{extracted => various}/gasleft_shadow_resolution.sol | 0 .../semanticTests/{extracted => various}/inline_member_init.sol | 0 .../{extracted => various}/inline_member_init_inheritence.sol | 0 .../{extracted => various}/inline_tuple_with_rational_numbers.sol | 0 .../semanticTests/{extracted => various}/iszero_bnot_correct.sol | 0 .../semanticTests/{extracted => various}/literal_empty_string.sol | 0 .../semanticTests/{extracted => various}/memory_overwrite.sol | 0 .../{extracted => various}/multi_variable_declaration.sol | 0 .../{extracted => various}/negative_stack_height.sol | 0 .../{extracted => various}/nested_calldata_struct.sol | 0 .../{extracted => various}/nested_calldata_struct_to_memory.sol | 0 .../{extracted => various}/positive_integers_to_signed.sol | 0 .../semanticTests/{extracted => various}/senders_balance.sol | 0 .../single_copy_with_multiple_inheritance.sol | 0 .../semanticTests/{extracted => various}/skip_dynamic_types.sol | 0 .../{extracted => various}/skip_dynamic_types_for_structs.sol | 0 .../state_variable_local_variable_mixture.sol | 0 .../{extracted => various}/state_variable_under_contract_name.sol | 0 .../storage_string_as_mapping_key_without_variable.sol | 0 .../semanticTests/{extracted => various}/store_bytes.sol | 0 .../semanticTests/{extracted => various}/string_tuples.sol | 0 test/libsolidity/semanticTests/{extracted => various}/super.sol | 0 .../semanticTests/{extracted => various}/super_alone.sol | 0 .../{extracted => various}/swap_in_storage_overwrite.sol | 0 .../{extracted => various}/test_underscore_in_hex.sol | 0 test/libsolidity/semanticTests/{extracted => various}/tuples.sol | 0 .../{extracted => various}/typed_multi_variable_declaration.sol | 0 .../semanticTests/{extracted => various}/value_complex.sol | 0 .../semanticTests/{extracted => various}/value_insane.sol | 0 .../{extracted => various}/write_storage_external.sol | 0 .../{extracted => virtualFunctions}/virtual_function_calls.sol | 0 .../virtual_function_usage_in_constructor_arguments.sol | 0 295 files changed, 0 insertions(+), 0 deletions(-) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_dynamic_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_static_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_static_array_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_trivial.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_v2_calldata.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_decode_v2_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_encode.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_encode_call.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_encode_decode_simple.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV1}/abi_encode_rational.sol (100%) rename test/libsolidity/semanticTests/{abiDecodeV1 => abiEncoderV1}/decode_slice.sol (100%) rename test/libsolidity/semanticTests/{abiDecodeV1 => abiEncoderV1}/dynamic_memory_copy.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV2}/abi_encode_empty_string_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV2}/abi_encode_rational_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiEncoderV2}/abi_encode_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => accessor}/accessor_for_const_state_variable.sol (100%) rename test/libsolidity/semanticTests/{extracted => accessor}/accessor_for_state_variable.sol (100%) rename test/libsolidity/semanticTests/{extracted => arithmetics}/addmod_mulmod.sol (100%) rename test/libsolidity/semanticTests/{extracted => arithmetics}/addmod_mulmod_zero.sol (100%) rename test/libsolidity/semanticTests/{extracted => arithmetics}/divisiod_by_zero.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_different_packing.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_nested_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_storage_abi_signed.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_storage_storage_static_dynamic.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_storage_storage_static_static.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_target_leftover2.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_copy_target_simple.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_pop.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_pop_empty_exception.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_pop_isolated.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_push.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_push_packed_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/array_push_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_pop.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_pop_copy_long.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_pop_empty_exception.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_pop_isolated.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_pop_masking_long.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_push.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/byte_array_push_transition.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/bytes_delete_element.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/bytes_length_member.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_array_dynamic_invalid.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_array_dynamic_invalid_static_middle.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_array_of_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_array_of_struct_to_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/calldata_dynamic_array_to_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/constant_var_as_array_length.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/copy_function_storage_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/copy_internal_function_array_to_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/create_dynamic_array_with_zero_length.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/create_memory_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/create_multiple_dynamic_arrays.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/delete_on_array_of_structs.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/dynamic_arrays_in_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/dynamic_out_of_bounds_array_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/evm_exceptions_out_of_band_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_arrays_as_return_type.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_arrays_in_constructors.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_bytes_length_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_out_of_bounds_array_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/function_array_cross_calls.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/function_memory_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_index_access_ints.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_index_access_strings.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_return.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_singleton.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_storage_to_memory_conversion_ints.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_storage_to_memory_conversion_strings.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/inline_array_strings_from_document.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/memory_arrays_of_various_sizes.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/storage_array_ref.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/keccak256_empty.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/keccak256_with_bytes.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/ripemd160_empty.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/sha256_empty.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_address_types_shortening.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_bytes_types_shortening.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_in_compound_assign.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/exp_cleanup.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/exp_cleanup_direct.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/exp_cleanup_nonzero_base.sol (100%) rename test/libsolidity/semanticTests/{extracted => constants}/constant_string.sol (100%) rename test/libsolidity/semanticTests/{extracted => constants}/constant_variables.sol (100%) rename test/libsolidity/semanticTests/{extracted => constants}/simple_constant_variables_test.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/base_constructor_arguments.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/constructor_arguments_external.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/constructor_arguments_internal.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/constructor_static_array_argument.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/evm_exceptions_in_constructor_call_fail.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/function_usage_in_constructor_arguments.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/functions_called_by_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/inline_member_init_inheritence_without_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/payable_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/store_function_in_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/store_internal_unused_function_in_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => constructor}/store_internal_unused_library_function_in_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/constructing_enums_from_ints.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/enum_explicit_overflow.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/using_contract_enums_with_explicit_contract_name.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/using_enums.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/using_inherited_enum.sol (100%) rename test/libsolidity/semanticTests/{extracted => enums}/using_inherited_enum_excplicitly.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/call_function_returning_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/calling_nonexisting_contract_throws.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/calling_uninitialized_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/calling_uninitialized_function_in_detail.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/calling_uninitialized_function_through_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/external_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/external_public_override.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/gas_and_value_basic.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/gas_and_value_brace_syntax.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/send_zero_ether.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/function_delete_stack.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/function_delete_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/function_type_library_internal.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/mapping_of_functions.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/pass_function_types_externally.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/pass_function_types_internally.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/same_function_in_construction_and_runtime.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/same_function_in_construction_and_runtime_equality_check.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/store_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionTypes}/uninitialized_internal_storage_function_call.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_embedded_function_call.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_for.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_for2.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_function_call.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_function_call2.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_function_call_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_if.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_in_modifiers.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_memory_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_read_and_write_stack.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_recursion.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_storage_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_storage_access_inside_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_storage_access_via_pointer.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_switch.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inline_assembly_write_to_stack.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/inlineasm_empty_let.sol (100%) rename test/libsolidity/semanticTests/{extracted => inlineAssembly}/keccak256_assembly.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/access_base_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/address_overload_resolution.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/base_access_to_function_type_variables.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/derived_overload_base_function_direct.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/derived_overload_base_function_indirect.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/explicit_base_class.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_constant_state_var.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_function_calldata_calldata_interface.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_function_calldata_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_function_calldata_memory_interface.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/inherited_function_from_a_library.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/overloaded_function_call_resolve_to_first.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/overloaded_function_call_resolve_to_second.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/overloaded_function_call_with_if_else.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/pass_dynamic_arguments_to_the_base.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/pass_dynamic_arguments_to_the_base_base.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/pass_dynamic_arguments_to_the_base_base_with_gap.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/super_in_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/super_overload.sol (100%) rename test/libsolidity/semanticTests/{extracted => intheritance}/value_for_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/internal_library_function.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/internal_library_function_bound.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/internal_library_function_calling_private.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/internal_library_function_return_var_size.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/library_enum_as_an_expression.sol (100%) rename test/libsolidity/semanticTests/{extracted => libraries}/library_struct_as_an_expression.sol (100%) rename test/libsolidity/semanticTests/{extracted => literals}/scientific_notation.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/break_in_modifier.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/continue_in_modifier.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_calling_functions_in_creation_context.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_for_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_library.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_library_inheritance.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_local_variables.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_loop.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_multi_invocation.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_multi_with_return.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_multiple_times.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_multiple_times_local_vars.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/function_modifier_overriding.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/return_does_not_skip_modifier.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/return_in_modifier.sol (100%) rename test/libsolidity/semanticTests/{extracted => modifiers}/stacked_return_with_modifiers.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/assert_require.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/invalid_enum_as_external_arg.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/invalid_enum_as_external_ret.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/invalid_enum_compared.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/invalid_enum_stored.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/invalid_instruction.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/revert.sol (100%) rename test/libsolidity/semanticTests/{extracted => reverts}/simple_throw.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_cleanup.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_cleanup_garbled.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_constant_left.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_constant_left_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_constant_right.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_constant_right_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left_assignment_different_type.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left_larger_type.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left_uint32.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_left_uint8.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_negative_constant_left.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_negative_constant_right.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_negative_rvalue.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_negative_rvalue_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_overflow.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_assignment_signed.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_literal.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_int16.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_int32.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_int8.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_uint32.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_uint8.sol (100%) rename test/libsolidity/semanticTests/{ => shifts}/shifts.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_functions.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_storage_overflow.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_storage_signed.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_storage_structs_bytes.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_storage_structs_enum.sol (100%) rename test/libsolidity/semanticTests/{extracted => storage}/packed_storage_structs_uint.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs/calldata}/calldata_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs/calldata}/calldata_struct_and_ints.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs/calldata}/calldata_struct_array_member.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs/calldata}/calldata_struct_to_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs/calldata}/calldata_structs.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/lone_struct_array_type.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/memory_structs_as_function_args.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/memory_structs_nested.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/memory_structs_read_write.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/memory_structs_with_mappings.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/recursive_structs.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_assign_reference_to_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_copy.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_copy_via_local.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_delete_member.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_delete_struct_in_mapping.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_named_constructor.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/assignment_to_const_var_involving_expression.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/balance.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/byte_optimization_bug.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/code_access_content.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/code_access_create.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/code_access_padding.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/contract_binary_dependencies.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/crazy_elementary_typenames_on_stack.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/cross_contract_types.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/decayed_tuple.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/destructuring_assignment.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/empty_name_return_parameter.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/external_types_in_calls.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/flipping_sign_tests.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/gasleft_decrease.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/gasleft_shadow_resolution.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/inline_member_init.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/inline_member_init_inheritence.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/inline_tuple_with_rational_numbers.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/iszero_bnot_correct.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/literal_empty_string.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/memory_overwrite.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/multi_variable_declaration.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/negative_stack_height.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/nested_calldata_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/nested_calldata_struct_to_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/positive_integers_to_signed.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/senders_balance.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/single_copy_with_multiple_inheritance.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/skip_dynamic_types.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/skip_dynamic_types_for_structs.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/state_variable_local_variable_mixture.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/state_variable_under_contract_name.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/storage_string_as_mapping_key_without_variable.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/store_bytes.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/string_tuples.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/super.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/super_alone.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/swap_in_storage_overwrite.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/test_underscore_in_hex.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/tuples.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/typed_multi_variable_declaration.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/value_complex.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/value_insane.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/write_storage_external.sol (100%) rename test/libsolidity/semanticTests/{extracted => virtualFunctions}/virtual_function_calls.sol (100%) rename test/libsolidity/semanticTests/{extracted => virtualFunctions}/virtual_function_usage_in_constructor_arguments.sol (100%) diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_dynamic_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_dynamic_array.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_dynamic_array.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_static_array.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_static_array_v2.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_static_array_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_trivial.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_trivial.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_trivial.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_v2.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_calldata.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_v2_calldata.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_calldata.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_v2_storage.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_encode.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_call.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_call.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_encode_call.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_decode_simple.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_decode_simple.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_encode_decode_simple.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_rational.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_rational.sol rename to test/libsolidity/semanticTests/abiEncoderV1/abi_encode_rational.sol diff --git a/test/libsolidity/semanticTests/abiDecodeV1/decode_slice.sol b/test/libsolidity/semanticTests/abiEncoderV1/decode_slice.sol similarity index 100% rename from test/libsolidity/semanticTests/abiDecodeV1/decode_slice.sol rename to test/libsolidity/semanticTests/abiEncoderV1/decode_slice.sol diff --git a/test/libsolidity/semanticTests/abiDecodeV1/dynamic_memory_copy.sol b/test/libsolidity/semanticTests/abiEncoderV1/dynamic_memory_copy.sol similarity index 100% rename from test/libsolidity/semanticTests/abiDecodeV1/dynamic_memory_copy.sol rename to test/libsolidity/semanticTests/abiEncoderV1/dynamic_memory_copy.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_empty_string_v2.sol rename to test/libsolidity/semanticTests/abiEncoderV2/abi_encode_empty_string_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_rational_v2.sol rename to test/libsolidity/semanticTests/abiEncoderV2/abi_encode_rational_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_v2.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_v2.sol rename to test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/accessor_for_const_state_variable.sol rename to test/libsolidity/semanticTests/accessor/accessor_for_const_state_variable.sol diff --git a/test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol b/test/libsolidity/semanticTests/accessor/accessor_for_state_variable.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/accessor_for_state_variable.sol rename to test/libsolidity/semanticTests/accessor/accessor_for_state_variable.sol diff --git a/test/libsolidity/semanticTests/extracted/addmod_mulmod.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/addmod_mulmod.sol rename to test/libsolidity/semanticTests/arithmetics/addmod_mulmod.sol diff --git a/test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol b/test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/addmod_mulmod_zero.sol rename to test/libsolidity/semanticTests/arithmetics/addmod_mulmod_zero.sol diff --git a/test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol b/test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/divisiod_by_zero.sol rename to test/libsolidity/semanticTests/arithmetics/divisiod_by_zero.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol b/test/libsolidity/semanticTests/array/array_copy_different_packing.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_different_packing.sol rename to test/libsolidity/semanticTests/array/array_copy_different_packing.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/array_copy_nested_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_nested_array.sol rename to test/libsolidity/semanticTests/array/array_copy_nested_array.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol b/test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_storage_abi_signed.sol rename to test/libsolidity/semanticTests/array/array_copy_storage_abi_signed.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_dynamic.sol rename to test/libsolidity/semanticTests/array/array_copy_storage_storage_static_dynamic.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_storage_storage_static_static.sol rename to test/libsolidity/semanticTests/array/array_copy_storage_storage_static_static.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol b/test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_target_leftover2.sol rename to test/libsolidity/semanticTests/array/array_copy_target_leftover2.sol diff --git a/test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol b/test/libsolidity/semanticTests/array/array_copy_target_simple.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_copy_target_simple.sol rename to test/libsolidity/semanticTests/array/array_copy_target_simple.sol diff --git a/test/libsolidity/semanticTests/extracted/array_pop.sol b/test/libsolidity/semanticTests/array/array_pop.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_pop.sol rename to test/libsolidity/semanticTests/array/array_pop.sol diff --git a/test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/array_pop_empty_exception.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_pop_empty_exception.sol rename to test/libsolidity/semanticTests/array/array_pop_empty_exception.sol diff --git a/test/libsolidity/semanticTests/extracted/array_pop_isolated.sol b/test/libsolidity/semanticTests/array/array_pop_isolated.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_pop_isolated.sol rename to test/libsolidity/semanticTests/array/array_pop_isolated.sol diff --git a/test/libsolidity/semanticTests/extracted/array_push.sol b/test/libsolidity/semanticTests/array/array_push.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_push.sol rename to test/libsolidity/semanticTests/array/array_push.sol diff --git a/test/libsolidity/semanticTests/extracted/array_push_packed_array.sol b/test/libsolidity/semanticTests/array/array_push_packed_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_push_packed_array.sol rename to test/libsolidity/semanticTests/array/array_push_packed_array.sol diff --git a/test/libsolidity/semanticTests/extracted/array_push_struct.sol b/test/libsolidity/semanticTests/array/array_push_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/array_push_struct.sol rename to test/libsolidity/semanticTests/array/array_push_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop.sol b/test/libsolidity/semanticTests/array/byte_array_pop.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_pop.sol rename to test/libsolidity/semanticTests/array/byte_array_pop.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol b/test/libsolidity/semanticTests/array/byte_array_pop_copy_long.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_pop_copy_long.sol rename to test/libsolidity/semanticTests/array/byte_array_pop_copy_long.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol b/test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_pop_empty_exception.sol rename to test/libsolidity/semanticTests/array/byte_array_pop_empty_exception.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol b/test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_pop_isolated.sol rename to test/libsolidity/semanticTests/array/byte_array_pop_isolated.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol b/test/libsolidity/semanticTests/array/byte_array_pop_masking_long.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_pop_masking_long.sol rename to test/libsolidity/semanticTests/array/byte_array_pop_masking_long.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_push.sol b/test/libsolidity/semanticTests/array/byte_array_push.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_push.sol rename to test/libsolidity/semanticTests/array/byte_array_push.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol b/test/libsolidity/semanticTests/array/byte_array_push_transition.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_array_push_transition.sol rename to test/libsolidity/semanticTests/array/byte_array_push_transition.sol diff --git a/test/libsolidity/semanticTests/extracted/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/bytes_delete_element.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bytes_delete_element.sol rename to test/libsolidity/semanticTests/array/bytes_delete_element.sol diff --git a/test/libsolidity/semanticTests/extracted/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bytes_length_member.sol rename to test/libsolidity/semanticTests/array/bytes_length_member.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array.sol b/test/libsolidity/semanticTests/array/calldata_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array.sol rename to test/libsolidity/semanticTests/array/calldata_array.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid.sol rename to test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol b/test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array_dynamic_invalid_static_middle.sol rename to test/libsolidity/semanticTests/array/calldata_array_dynamic_invalid_static_middle.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol b/test/libsolidity/semanticTests/array/calldata_array_of_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array_of_struct.sol rename to test/libsolidity/semanticTests/array/calldata_array_of_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol b/test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array_of_struct_to_memory.sol rename to test/libsolidity/semanticTests/array/calldata_array_of_struct_to_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol b/test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_dynamic_array_to_memory.sol rename to test/libsolidity/semanticTests/array/calldata_dynamic_array_to_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constant_var_as_array_length.sol rename to test/libsolidity/semanticTests/array/constant_var_as_array_length.sol diff --git a/test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol b/test/libsolidity/semanticTests/array/copy_function_storage_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/copy_function_storage_array.sol rename to test/libsolidity/semanticTests/array/copy_function_storage_array.sol diff --git a/test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/copy_internal_function_array_to_storage.sol rename to test/libsolidity/semanticTests/array/copy_internal_function_array_to_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol b/test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/create_dynamic_array_with_zero_length.sol rename to test/libsolidity/semanticTests/array/create_dynamic_array_with_zero_length.sol diff --git a/test/libsolidity/semanticTests/extracted/create_memory_array.sol b/test/libsolidity/semanticTests/array/create_memory_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/create_memory_array.sol rename to test/libsolidity/semanticTests/array/create_memory_array.sol diff --git a/test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol b/test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/create_multiple_dynamic_arrays.sol rename to test/libsolidity/semanticTests/array/create_multiple_dynamic_arrays.sol diff --git a/test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol b/test/libsolidity/semanticTests/array/delete_on_array_of_structs.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/delete_on_array_of_structs.sol rename to test/libsolidity/semanticTests/array/delete_on_array_of_structs.sol diff --git a/test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol b/test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/dynamic_arrays_in_storage.sol rename to test/libsolidity/semanticTests/array/dynamic_arrays_in_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/array/dynamic_out_of_bounds_array_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/dynamic_out_of_bounds_array_access.sol rename to test/libsolidity/semanticTests/array/dynamic_out_of_bounds_array_access.sol diff --git a/test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol b/test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/evm_exceptions_out_of_band_access.sol rename to test/libsolidity/semanticTests/array/evm_exceptions_out_of_band_access.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_arrays_as_return_type.sol rename to test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_arrays_in_constructors.sol rename to test/libsolidity/semanticTests/array/fixed_arrays_in_constructors.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_bytes_length_access.sol rename to test/libsolidity/semanticTests/array/fixed_bytes_length_access.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol b/test/libsolidity/semanticTests/array/fixed_out_of_bounds_array_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_out_of_bounds_array_access.sol rename to test/libsolidity/semanticTests/array/fixed_out_of_bounds_array_access.sol diff --git a/test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_array_cross_calls.sol rename to test/libsolidity/semanticTests/array/function_array_cross_calls.sol diff --git a/test/libsolidity/semanticTests/extracted/function_memory_array.sol b/test/libsolidity/semanticTests/array/function_memory_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_memory_array.sol rename to test/libsolidity/semanticTests/array/function_memory_array.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol b/test/libsolidity/semanticTests/array/inline_array_index_access_ints.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_index_access_ints.sol rename to test/libsolidity/semanticTests/array/inline_array_index_access_ints.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol b/test/libsolidity/semanticTests/array/inline_array_index_access_strings.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_index_access_strings.sol rename to test/libsolidity/semanticTests/array/inline_array_index_access_strings.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_return.sol b/test/libsolidity/semanticTests/array/inline_array_return.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_return.sol rename to test/libsolidity/semanticTests/array/inline_array_return.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_singleton.sol b/test/libsolidity/semanticTests/array/inline_array_singleton.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_singleton.sol rename to test/libsolidity/semanticTests/array/inline_array_singleton.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_ints.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_ints.sol rename to test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_ints.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol b/test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_strings.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_storage_to_memory_conversion_strings.sol rename to test/libsolidity/semanticTests/array/inline_array_storage_to_memory_conversion_strings.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol b/test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_array_strings_from_document.sol rename to test/libsolidity/semanticTests/array/inline_array_strings_from_document.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol b/test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_arrays_of_various_sizes.sol rename to test/libsolidity/semanticTests/array/memory_arrays_of_various_sizes.sol diff --git a/test/libsolidity/semanticTests/extracted/storage_array_ref.sol b/test/libsolidity/semanticTests/array/storage_array_ref.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/storage_array_ref.sol rename to test/libsolidity/semanticTests/array/storage_array_ref.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_empty.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_empty.sol rename to test/libsolidity/semanticTests/builtinFunctions/keccak256_empty.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_with_bytes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_with_bytes.sol rename to test/libsolidity/semanticTests/builtinFunctions/keccak256_with_bytes.sol diff --git a/test/libsolidity/semanticTests/extracted/ripemd160_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/ripemd160_empty.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/ripemd160_empty.sol rename to test/libsolidity/semanticTests/builtinFunctions/ripemd160_empty.sol diff --git a/test/libsolidity/semanticTests/extracted/sha256_empty.sol b/test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/sha256_empty.sol rename to test/libsolidity/semanticTests/builtinFunctions/sha256_empty.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_shortening.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_address_types_shortening.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_address_types_shortening.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_bytes_types_shortening.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_shortening.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol b/test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_in_compound_assign.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_in_compound_assign.sol diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/exp_cleanup.sol rename to test/libsolidity/semanticTests/cleanup/exp_cleanup.sol diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup_direct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/exp_cleanup_direct.sol rename to test/libsolidity/semanticTests/cleanup/exp_cleanup_direct.sol diff --git a/test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol b/test/libsolidity/semanticTests/cleanup/exp_cleanup_nonzero_base.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/exp_cleanup_nonzero_base.sol rename to test/libsolidity/semanticTests/cleanup/exp_cleanup_nonzero_base.sol diff --git a/test/libsolidity/semanticTests/extracted/constant_string.sol b/test/libsolidity/semanticTests/constants/constant_string.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constant_string.sol rename to test/libsolidity/semanticTests/constants/constant_string.sol diff --git a/test/libsolidity/semanticTests/extracted/constant_variables.sol b/test/libsolidity/semanticTests/constants/constant_variables.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constant_variables.sol rename to test/libsolidity/semanticTests/constants/constant_variables.sol diff --git a/test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol b/test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/simple_constant_variables_test.sol rename to test/libsolidity/semanticTests/constants/simple_constant_variables_test.sol diff --git a/test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/base_constructor_arguments.sol rename to test/libsolidity/semanticTests/constructor/base_constructor_arguments.sol diff --git a/test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constructor_arguments_external.sol rename to test/libsolidity/semanticTests/constructor/constructor_arguments_external.sol diff --git a/test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol b/test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constructor_arguments_internal.sol rename to test/libsolidity/semanticTests/constructor/constructor_arguments_internal.sol diff --git a/test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constructor_static_array_argument.sol rename to test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol diff --git a/test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol b/test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/evm_exceptions_in_constructor_call_fail.sol rename to test/libsolidity/semanticTests/constructor/evm_exceptions_in_constructor_call_fail.sol diff --git a/test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_usage_in_constructor_arguments.sol rename to test/libsolidity/semanticTests/constructor/function_usage_in_constructor_arguments.sol diff --git a/test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol b/test/libsolidity/semanticTests/constructor/functions_called_by_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/functions_called_by_constructor.sol rename to test/libsolidity/semanticTests/constructor/functions_called_by_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol b/test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_member_init_inheritence_without_constructor.sol rename to test/libsolidity/semanticTests/constructor/inline_member_init_inheritence_without_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/payable_constructor.sol b/test/libsolidity/semanticTests/constructor/payable_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/payable_constructor.sol rename to test/libsolidity/semanticTests/constructor/payable_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/store_function_in_constructor.sol rename to test/libsolidity/semanticTests/constructor/store_function_in_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/store_internal_unused_function_in_constructor.sol rename to test/libsolidity/semanticTests/constructor/store_internal_unused_function_in_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol b/test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/store_internal_unused_library_function_in_constructor.sol rename to test/libsolidity/semanticTests/constructor/store_internal_unused_library_function_in_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol b/test/libsolidity/semanticTests/enums/constructing_enums_from_ints.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/constructing_enums_from_ints.sol rename to test/libsolidity/semanticTests/enums/constructing_enums_from_ints.sol diff --git a/test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol b/test/libsolidity/semanticTests/enums/enum_explicit_overflow.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/enum_explicit_overflow.sol rename to test/libsolidity/semanticTests/enums/enum_explicit_overflow.sol diff --git a/test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol b/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/using_contract_enums_with_explicit_contract_name.sol rename to test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol diff --git a/test/libsolidity/semanticTests/extracted/using_enums.sol b/test/libsolidity/semanticTests/enums/using_enums.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/using_enums.sol rename to test/libsolidity/semanticTests/enums/using_enums.sol diff --git a/test/libsolidity/semanticTests/extracted/using_inherited_enum.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/using_inherited_enum.sol rename to test/libsolidity/semanticTests/enums/using_inherited_enum.sol diff --git a/test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/using_inherited_enum_excplicitly.sol rename to test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol diff --git a/test/libsolidity/semanticTests/extracted/call_function_returning_function.sol b/test/libsolidity/semanticTests/functionCall/call_function_returning_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/call_function_returning_function.sol rename to test/libsolidity/semanticTests/functionCall/call_function_returning_function.sol diff --git a/test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol b/test/libsolidity/semanticTests/functionCall/calling_nonexisting_contract_throws.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calling_nonexisting_contract_throws.sol rename to test/libsolidity/semanticTests/functionCall/calling_nonexisting_contract_throws.sol diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calling_uninitialized_function.sol rename to test/libsolidity/semanticTests/functionCall/calling_uninitialized_function.sol diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calling_uninitialized_function_in_detail.sol rename to test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_in_detail.sol diff --git a/test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol b/test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calling_uninitialized_function_through_array.sol rename to test/libsolidity/semanticTests/functionCall/calling_uninitialized_function_through_array.sol diff --git a/test/libsolidity/semanticTests/extracted/external_function.sol b/test/libsolidity/semanticTests/functionCall/external_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/external_function.sol rename to test/libsolidity/semanticTests/functionCall/external_function.sol diff --git a/test/libsolidity/semanticTests/extracted/external_public_override.sol b/test/libsolidity/semanticTests/functionCall/external_public_override.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/external_public_override.sol rename to test/libsolidity/semanticTests/functionCall/external_public_override.sol diff --git a/test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/gas_and_value_basic.sol rename to test/libsolidity/semanticTests/functionCall/gas_and_value_basic.sol diff --git a/test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol b/test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/gas_and_value_brace_syntax.sol rename to test/libsolidity/semanticTests/functionCall/gas_and_value_brace_syntax.sol diff --git a/test/libsolidity/semanticTests/extracted/send_zero_ether.sol b/test/libsolidity/semanticTests/functionCall/send_zero_ether.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/send_zero_ether.sol rename to test/libsolidity/semanticTests/functionCall/send_zero_ether.sol diff --git a/test/libsolidity/semanticTests/extracted/function_delete_stack.sol b/test/libsolidity/semanticTests/functionTypes/function_delete_stack.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_delete_stack.sol rename to test/libsolidity/semanticTests/functionTypes/function_delete_stack.sol diff --git a/test/libsolidity/semanticTests/extracted/function_delete_storage.sol b/test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_delete_storage.sol rename to test/libsolidity/semanticTests/functionTypes/function_delete_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/function_type_library_internal.sol b/test/libsolidity/semanticTests/functionTypes/function_type_library_internal.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_type_library_internal.sol rename to test/libsolidity/semanticTests/functionTypes/function_type_library_internal.sol diff --git a/test/libsolidity/semanticTests/extracted/mapping_of_functions.sol b/test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/mapping_of_functions.sol rename to test/libsolidity/semanticTests/functionTypes/mapping_of_functions.sol diff --git a/test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/pass_function_types_externally.sol rename to test/libsolidity/semanticTests/functionTypes/pass_function_types_externally.sol diff --git a/test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol b/test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/pass_function_types_internally.sol rename to test/libsolidity/semanticTests/functionTypes/pass_function_types_internally.sol diff --git a/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime.sol rename to test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime.sol diff --git a/test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol b/test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/same_function_in_construction_and_runtime_equality_check.sol rename to test/libsolidity/semanticTests/functionTypes/same_function_in_construction_and_runtime_equality_check.sol diff --git a/test/libsolidity/semanticTests/extracted/store_function.sol b/test/libsolidity/semanticTests/functionTypes/store_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/store_function.sol rename to test/libsolidity/semanticTests/functionTypes/store_function.sol diff --git a/test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol b/test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/uninitialized_internal_storage_function_call.sol rename to test/libsolidity/semanticTests/functionTypes/uninitialized_internal_storage_function_call.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_embedded_function_call.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_embedded_function_call.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_embedded_function_call.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_for.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_for.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_for2.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_for2.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_function_call.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_function_call2.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call2.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_function_call_assignment.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_function_call_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_if.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_if.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_if.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_if.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_in_modifiers.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_in_modifiers.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_in_modifiers.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_memory_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_memory_access.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_memory_access.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_read_and_write_stack.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_read_and_write_stack.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_read_and_write_stack.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_recursion.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_recursion.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_recursion.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_storage_access.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_inside_function.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_inside_function.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_via_pointer.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_storage_access_via_pointer.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_storage_access_via_pointer.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_switch.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_switch.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_switch.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol b/test/libsolidity/semanticTests/inlineAssembly/inline_assembly_write_to_stack.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_assembly_write_to_stack.sol rename to test/libsolidity/semanticTests/inlineAssembly/inline_assembly_write_to_stack.sol diff --git a/test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol b/test/libsolidity/semanticTests/inlineAssembly/inlineasm_empty_let.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inlineasm_empty_let.sol rename to test/libsolidity/semanticTests/inlineAssembly/inlineasm_empty_let.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_assembly.sol b/test/libsolidity/semanticTests/inlineAssembly/keccak256_assembly.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_assembly.sol rename to test/libsolidity/semanticTests/inlineAssembly/keccak256_assembly.sol diff --git a/test/libsolidity/semanticTests/extracted/access_base_storage.sol b/test/libsolidity/semanticTests/intheritance/access_base_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/access_base_storage.sol rename to test/libsolidity/semanticTests/intheritance/access_base_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/address_overload_resolution.sol b/test/libsolidity/semanticTests/intheritance/address_overload_resolution.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/address_overload_resolution.sol rename to test/libsolidity/semanticTests/intheritance/address_overload_resolution.sol diff --git a/test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol b/test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/base_access_to_function_type_variables.sol rename to test/libsolidity/semanticTests/intheritance/base_access_to_function_type_variables.sol diff --git a/test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_direct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/derived_overload_base_function_direct.sol rename to test/libsolidity/semanticTests/intheritance/derived_overload_base_function_direct.sol diff --git a/test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol b/test/libsolidity/semanticTests/intheritance/derived_overload_base_function_indirect.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/derived_overload_base_function_indirect.sol rename to test/libsolidity/semanticTests/intheritance/derived_overload_base_function_indirect.sol diff --git a/test/libsolidity/semanticTests/extracted/explicit_base_class.sol b/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/explicit_base_class.sol rename to test/libsolidity/semanticTests/intheritance/explicit_base_class.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol b/test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_constant_state_var.sol rename to test/libsolidity/semanticTests/intheritance/inherited_constant_state_var.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_function.sol b/test/libsolidity/semanticTests/intheritance/inherited_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_function.sol rename to test/libsolidity/semanticTests/intheritance/inherited_function.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_calldata_interface.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_function_calldata_calldata_interface.sol rename to test/libsolidity/semanticTests/intheritance/inherited_function_calldata_calldata_interface.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory.sol rename to test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory_interface.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_function_calldata_memory_interface.sol rename to test/libsolidity/semanticTests/intheritance/inherited_function_calldata_memory_interface.sol diff --git a/test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol b/test/libsolidity/semanticTests/intheritance/inherited_function_from_a_library.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inherited_function_from_a_library.sol rename to test/libsolidity/semanticTests/intheritance/inherited_function_from_a_library.sol diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_first.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_first.sol rename to test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_first.sol diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_second.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/overloaded_function_call_resolve_to_second.sol rename to test/libsolidity/semanticTests/intheritance/overloaded_function_call_resolve_to_second.sol diff --git a/test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol b/test/libsolidity/semanticTests/intheritance/overloaded_function_call_with_if_else.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/overloaded_function_call_with_if_else.sol rename to test/libsolidity/semanticTests/intheritance/overloaded_function_call_with_if_else.sol diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base.sol rename to test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base.sol diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base.sol rename to test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base.sol diff --git a/test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol b/test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/pass_dynamic_arguments_to_the_base_base_with_gap.sol rename to test/libsolidity/semanticTests/intheritance/pass_dynamic_arguments_to_the_base_base_with_gap.sol diff --git a/test/libsolidity/semanticTests/extracted/super_in_constructor.sol b/test/libsolidity/semanticTests/intheritance/super_in_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/super_in_constructor.sol rename to test/libsolidity/semanticTests/intheritance/super_in_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/super_overload.sol b/test/libsolidity/semanticTests/intheritance/super_overload.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/super_overload.sol rename to test/libsolidity/semanticTests/intheritance/super_overload.sol diff --git a/test/libsolidity/semanticTests/extracted/value_for_constructor.sol b/test/libsolidity/semanticTests/intheritance/value_for_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/value_for_constructor.sol rename to test/libsolidity/semanticTests/intheritance/value_for_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function.sol b/test/libsolidity/semanticTests/libraries/internal_library_function.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/internal_library_function.sol rename to test/libsolidity/semanticTests/libraries/internal_library_function.sol diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_bound.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/internal_library_function_bound.sol rename to test/libsolidity/semanticTests/libraries/internal_library_function_bound.sol diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_calling_private.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/internal_library_function_calling_private.sol rename to test/libsolidity/semanticTests/libraries/internal_library_function_calling_private.sol diff --git a/test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol b/test/libsolidity/semanticTests/libraries/internal_library_function_return_var_size.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/internal_library_function_return_var_size.sol rename to test/libsolidity/semanticTests/libraries/internal_library_function_return_var_size.sol diff --git a/test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/library_enum_as_an_expression.sol rename to test/libsolidity/semanticTests/libraries/library_enum_as_an_expression.sol diff --git a/test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol b/test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/library_struct_as_an_expression.sol rename to test/libsolidity/semanticTests/libraries/library_struct_as_an_expression.sol diff --git a/test/libsolidity/semanticTests/extracted/scientific_notation.sol b/test/libsolidity/semanticTests/literals/scientific_notation.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/scientific_notation.sol rename to test/libsolidity/semanticTests/literals/scientific_notation.sol diff --git a/test/libsolidity/semanticTests/extracted/break_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/break_in_modifier.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/break_in_modifier.sol rename to test/libsolidity/semanticTests/modifiers/break_in_modifier.sol diff --git a/test/libsolidity/semanticTests/extracted/continue_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/continue_in_modifier.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/continue_in_modifier.sol rename to test/libsolidity/semanticTests/modifiers/continue_in_modifier.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier.sol b/test/libsolidity/semanticTests/modifiers/function_modifier.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_calling_functions_in_creation_context.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_calling_functions_in_creation_context.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_calling_functions_in_creation_context.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_for_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_for_constructor.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_for_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_library.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_library.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_library.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_library.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_library_inheritance.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_library_inheritance.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_library_inheritance.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_local_variables.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_local_variables.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_local_variables.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_loop.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_loop.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_loop.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_loop.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_invocation.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_multi_invocation.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_multi_invocation.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multi_with_return.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_multi_with_return.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_multi_with_return.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_multiple_times.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times_local_vars.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_multiple_times_local_vars.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_multiple_times_local_vars.sol diff --git a/test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol b/test/libsolidity/semanticTests/modifiers/function_modifier_overriding.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_modifier_overriding.sol rename to test/libsolidity/semanticTests/modifiers/function_modifier_overriding.sol diff --git a/test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol b/test/libsolidity/semanticTests/modifiers/return_does_not_skip_modifier.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/return_does_not_skip_modifier.sol rename to test/libsolidity/semanticTests/modifiers/return_does_not_skip_modifier.sol diff --git a/test/libsolidity/semanticTests/extracted/return_in_modifier.sol b/test/libsolidity/semanticTests/modifiers/return_in_modifier.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/return_in_modifier.sol rename to test/libsolidity/semanticTests/modifiers/return_in_modifier.sol diff --git a/test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol b/test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/stacked_return_with_modifiers.sol rename to test/libsolidity/semanticTests/modifiers/stacked_return_with_modifiers.sol diff --git a/test/libsolidity/semanticTests/extracted/assert_require.sol b/test/libsolidity/semanticTests/reverts/assert_require.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/assert_require.sol rename to test/libsolidity/semanticTests/reverts/assert_require.sol diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/invalid_enum_as_external_arg.sol rename to test/libsolidity/semanticTests/reverts/invalid_enum_as_external_arg.sol diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_as_external_ret.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/invalid_enum_as_external_ret.sol rename to test/libsolidity/semanticTests/reverts/invalid_enum_as_external_ret.sol diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/invalid_enum_compared.sol rename to test/libsolidity/semanticTests/reverts/invalid_enum_compared.sol diff --git a/test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol b/test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/invalid_enum_stored.sol rename to test/libsolidity/semanticTests/reverts/invalid_enum_stored.sol diff --git a/test/libsolidity/semanticTests/extracted/invalid_instruction.sol b/test/libsolidity/semanticTests/reverts/invalid_instruction.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/invalid_instruction.sol rename to test/libsolidity/semanticTests/reverts/invalid_instruction.sol diff --git a/test/libsolidity/semanticTests/extracted/revert.sol b/test/libsolidity/semanticTests/reverts/revert.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/revert.sol rename to test/libsolidity/semanticTests/reverts/revert.sol diff --git a/test/libsolidity/semanticTests/extracted/simple_throw.sol b/test/libsolidity/semanticTests/reverts/simple_throw.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/simple_throw.sol rename to test/libsolidity/semanticTests/reverts/simple_throw.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_cleanup.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_cleanup.sol rename to test/libsolidity/semanticTests/shifts/shift_cleanup.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_cleanup_garbled.sol rename to test/libsolidity/semanticTests/shifts/shift_cleanup_garbled.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_constant_left.sol rename to test/libsolidity/semanticTests/shifts/shift_constant_left.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_constant_left_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_constant_left_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_constant_right.sol rename to test/libsolidity/semanticTests/shifts/shift_constant_right.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_constant_right_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_constant_right_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left.sol b/test/libsolidity/semanticTests/shifts/shift_left.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left.sol rename to test/libsolidity/semanticTests/shifts/shift_left.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_left_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left_assignment_different_type.sol rename to test/libsolidity/semanticTests/shifts/shift_left_assignment_different_type.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol b/test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left_larger_type.sol rename to test/libsolidity/semanticTests/shifts/shift_left_larger_type.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint32.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left_uint32.sol rename to test/libsolidity/semanticTests/shifts/shift_left_uint32.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_left_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_left_uint8.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_left_uint8.sol rename to test/libsolidity/semanticTests/shifts/shift_left_uint8.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_negative_constant_left.sol rename to test/libsolidity/semanticTests/shifts/shift_negative_constant_left.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol b/test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_negative_constant_right.sol rename to test/libsolidity/semanticTests/shifts/shift_negative_constant_right.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_negative_rvalue.sol rename to test/libsolidity/semanticTests/shifts/shift_negative_rvalue.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_negative_rvalue_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_negative_rvalue_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_overflow.sol b/test/libsolidity/semanticTests/shifts/shift_overflow.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_overflow.sol rename to test/libsolidity/semanticTests/shifts/shift_overflow.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right.sol b/test/libsolidity/semanticTests/shifts/shift_right.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right.sol rename to test/libsolidity/semanticTests/shifts/shift_right.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_right_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_assignment_signed.sol rename to test/libsolidity/semanticTests/shifts/shift_right_assignment_signed.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_literal.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_literal.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_assignment.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int16.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int16.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int32.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int32.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_int8.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_int8.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_uint32.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint32.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_uint32.sol rename to test/libsolidity/semanticTests/shifts/shift_right_uint32.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_uint8.sol b/test/libsolidity/semanticTests/shifts/shift_right_uint8.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_uint8.sol rename to test/libsolidity/semanticTests/shifts/shift_right_uint8.sol diff --git a/test/libsolidity/semanticTests/shifts.sol b/test/libsolidity/semanticTests/shifts/shifts.sol similarity index 100% rename from test/libsolidity/semanticTests/shifts.sol rename to test/libsolidity/semanticTests/shifts/shifts.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_functions.sol b/test/libsolidity/semanticTests/storage/packed_functions.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_functions.sol rename to test/libsolidity/semanticTests/storage/packed_functions.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol b/test/libsolidity/semanticTests/storage/packed_storage_overflow.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_storage_overflow.sol rename to test/libsolidity/semanticTests/storage/packed_storage_overflow.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_signed.sol b/test/libsolidity/semanticTests/storage/packed_storage_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_storage_signed.sol rename to test/libsolidity/semanticTests/storage/packed_storage_signed.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_bytes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_storage_structs_bytes.sol rename to test/libsolidity/semanticTests/storage/packed_storage_structs_bytes.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_enum.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_storage_structs_enum.sol rename to test/libsolidity/semanticTests/storage/packed_storage_structs_enum.sol diff --git a/test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol b/test/libsolidity/semanticTests/storage/packed_storage_structs_uint.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/packed_storage_structs_uint.sol rename to test/libsolidity/semanticTests/storage/packed_storage_structs_uint.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_struct.sol rename to test/libsolidity/semanticTests/structs/calldata/calldata_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_and_ints.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_struct_and_ints.sol rename to test/libsolidity/semanticTests/structs/calldata/calldata_struct_and_ints.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_array_member.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_struct_array_member.sol rename to test/libsolidity/semanticTests/structs/calldata/calldata_struct_array_member.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_struct_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_struct_to_memory.sol rename to test/libsolidity/semanticTests/structs/calldata/calldata_struct_to_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_structs.sol b/test/libsolidity/semanticTests/structs/calldata/calldata_structs.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_structs.sol rename to test/libsolidity/semanticTests/structs/calldata/calldata_structs.sol diff --git a/test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol b/test/libsolidity/semanticTests/structs/lone_struct_array_type.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/lone_struct_array_type.sol rename to test/libsolidity/semanticTests/structs/lone_struct_array_type.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol b/test/libsolidity/semanticTests/structs/memory_structs_as_function_args.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_structs_as_function_args.sol rename to test/libsolidity/semanticTests/structs/memory_structs_as_function_args.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_nested.sol b/test/libsolidity/semanticTests/structs/memory_structs_nested.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_structs_nested.sol rename to test/libsolidity/semanticTests/structs/memory_structs_nested.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol b/test/libsolidity/semanticTests/structs/memory_structs_read_write.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_structs_read_write.sol rename to test/libsolidity/semanticTests/structs/memory_structs_read_write.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol b/test/libsolidity/semanticTests/structs/memory_structs_with_mappings.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_structs_with_mappings.sol rename to test/libsolidity/semanticTests/structs/memory_structs_with_mappings.sol diff --git a/test/libsolidity/semanticTests/extracted/recursive_structs.sol b/test/libsolidity/semanticTests/structs/recursive_structs.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/recursive_structs.sol rename to test/libsolidity/semanticTests/structs/recursive_structs.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol b/test/libsolidity/semanticTests/structs/struct_assign_reference_to_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_assign_reference_to_struct.sol rename to test/libsolidity/semanticTests/structs/struct_assign_reference_to_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_copy.sol b/test/libsolidity/semanticTests/structs/struct_copy.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_copy.sol rename to test/libsolidity/semanticTests/structs/struct_copy.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol b/test/libsolidity/semanticTests/structs/struct_copy_via_local.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_copy_via_local.sol rename to test/libsolidity/semanticTests/structs/struct_copy_via_local.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_delete_member.sol b/test/libsolidity/semanticTests/structs/struct_delete_member.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_delete_member.sol rename to test/libsolidity/semanticTests/structs/struct_delete_member.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol b/test/libsolidity/semanticTests/structs/struct_delete_struct_in_mapping.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_delete_struct_in_mapping.sol rename to test/libsolidity/semanticTests/structs/struct_delete_struct_in_mapping.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_named_constructor.sol b/test/libsolidity/semanticTests/structs/struct_named_constructor.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_named_constructor.sol rename to test/libsolidity/semanticTests/structs/struct_named_constructor.sol diff --git a/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol b/test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_expression.sol rename to test/libsolidity/semanticTests/various/assignment_to_const_var_involving_expression.sol diff --git a/test/libsolidity/semanticTests/extracted/balance.sol b/test/libsolidity/semanticTests/various/balance.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/balance.sol rename to test/libsolidity/semanticTests/various/balance.sol diff --git a/test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol b/test/libsolidity/semanticTests/various/byte_optimization_bug.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/byte_optimization_bug.sol rename to test/libsolidity/semanticTests/various/byte_optimization_bug.sol diff --git a/test/libsolidity/semanticTests/extracted/code_access_content.sol b/test/libsolidity/semanticTests/various/code_access_content.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/code_access_content.sol rename to test/libsolidity/semanticTests/various/code_access_content.sol diff --git a/test/libsolidity/semanticTests/extracted/code_access_create.sol b/test/libsolidity/semanticTests/various/code_access_create.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/code_access_create.sol rename to test/libsolidity/semanticTests/various/code_access_create.sol diff --git a/test/libsolidity/semanticTests/extracted/code_access_padding.sol b/test/libsolidity/semanticTests/various/code_access_padding.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/code_access_padding.sol rename to test/libsolidity/semanticTests/various/code_access_padding.sol diff --git a/test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol b/test/libsolidity/semanticTests/various/contract_binary_dependencies.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/contract_binary_dependencies.sol rename to test/libsolidity/semanticTests/various/contract_binary_dependencies.sol diff --git a/test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol b/test/libsolidity/semanticTests/various/crazy_elementary_typenames_on_stack.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/crazy_elementary_typenames_on_stack.sol rename to test/libsolidity/semanticTests/various/crazy_elementary_typenames_on_stack.sol diff --git a/test/libsolidity/semanticTests/extracted/cross_contract_types.sol b/test/libsolidity/semanticTests/various/cross_contract_types.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cross_contract_types.sol rename to test/libsolidity/semanticTests/various/cross_contract_types.sol diff --git a/test/libsolidity/semanticTests/extracted/decayed_tuple.sol b/test/libsolidity/semanticTests/various/decayed_tuple.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/decayed_tuple.sol rename to test/libsolidity/semanticTests/various/decayed_tuple.sol diff --git a/test/libsolidity/semanticTests/extracted/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/destructuring_assignment.sol rename to test/libsolidity/semanticTests/various/destructuring_assignment.sol diff --git a/test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol b/test/libsolidity/semanticTests/various/empty_name_return_parameter.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/empty_name_return_parameter.sol rename to test/libsolidity/semanticTests/various/empty_name_return_parameter.sol diff --git a/test/libsolidity/semanticTests/extracted/external_types_in_calls.sol b/test/libsolidity/semanticTests/various/external_types_in_calls.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/external_types_in_calls.sol rename to test/libsolidity/semanticTests/various/external_types_in_calls.sol diff --git a/test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol b/test/libsolidity/semanticTests/various/flipping_sign_tests.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/flipping_sign_tests.sol rename to test/libsolidity/semanticTests/various/flipping_sign_tests.sol diff --git a/test/libsolidity/semanticTests/extracted/gasleft_decrease.sol b/test/libsolidity/semanticTests/various/gasleft_decrease.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/gasleft_decrease.sol rename to test/libsolidity/semanticTests/various/gasleft_decrease.sol diff --git a/test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol b/test/libsolidity/semanticTests/various/gasleft_shadow_resolution.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/gasleft_shadow_resolution.sol rename to test/libsolidity/semanticTests/various/gasleft_shadow_resolution.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init.sol b/test/libsolidity/semanticTests/various/inline_member_init.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_member_init.sol rename to test/libsolidity/semanticTests/various/inline_member_init.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol b/test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_member_init_inheritence.sol rename to test/libsolidity/semanticTests/various/inline_member_init_inheritence.sol diff --git a/test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol b/test/libsolidity/semanticTests/various/inline_tuple_with_rational_numbers.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/inline_tuple_with_rational_numbers.sol rename to test/libsolidity/semanticTests/various/inline_tuple_with_rational_numbers.sol diff --git a/test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol b/test/libsolidity/semanticTests/various/iszero_bnot_correct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/iszero_bnot_correct.sol rename to test/libsolidity/semanticTests/various/iszero_bnot_correct.sol diff --git a/test/libsolidity/semanticTests/extracted/literal_empty_string.sol b/test/libsolidity/semanticTests/various/literal_empty_string.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/literal_empty_string.sol rename to test/libsolidity/semanticTests/various/literal_empty_string.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_overwrite.sol b/test/libsolidity/semanticTests/various/memory_overwrite.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_overwrite.sol rename to test/libsolidity/semanticTests/various/memory_overwrite.sol diff --git a/test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/multi_variable_declaration.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/multi_variable_declaration.sol rename to test/libsolidity/semanticTests/various/multi_variable_declaration.sol diff --git a/test/libsolidity/semanticTests/extracted/negative_stack_height.sol b/test/libsolidity/semanticTests/various/negative_stack_height.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/negative_stack_height.sol rename to test/libsolidity/semanticTests/various/negative_stack_height.sol diff --git a/test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol b/test/libsolidity/semanticTests/various/nested_calldata_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/nested_calldata_struct.sol rename to test/libsolidity/semanticTests/various/nested_calldata_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol b/test/libsolidity/semanticTests/various/nested_calldata_struct_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/nested_calldata_struct_to_memory.sol rename to test/libsolidity/semanticTests/various/nested_calldata_struct_to_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol b/test/libsolidity/semanticTests/various/positive_integers_to_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/positive_integers_to_signed.sol rename to test/libsolidity/semanticTests/various/positive_integers_to_signed.sol diff --git a/test/libsolidity/semanticTests/extracted/senders_balance.sol b/test/libsolidity/semanticTests/various/senders_balance.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/senders_balance.sol rename to test/libsolidity/semanticTests/various/senders_balance.sol diff --git a/test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol b/test/libsolidity/semanticTests/various/single_copy_with_multiple_inheritance.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/single_copy_with_multiple_inheritance.sol rename to test/libsolidity/semanticTests/various/single_copy_with_multiple_inheritance.sol diff --git a/test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/skip_dynamic_types.sol rename to test/libsolidity/semanticTests/various/skip_dynamic_types.sol diff --git a/test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol b/test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/skip_dynamic_types_for_structs.sol rename to test/libsolidity/semanticTests/various/skip_dynamic_types_for_structs.sol diff --git a/test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol b/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/state_variable_local_variable_mixture.sol rename to test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol diff --git a/test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol b/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/state_variable_under_contract_name.sol rename to test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol diff --git a/test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol b/test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/storage_string_as_mapping_key_without_variable.sol rename to test/libsolidity/semanticTests/various/storage_string_as_mapping_key_without_variable.sol diff --git a/test/libsolidity/semanticTests/extracted/store_bytes.sol b/test/libsolidity/semanticTests/various/store_bytes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/store_bytes.sol rename to test/libsolidity/semanticTests/various/store_bytes.sol diff --git a/test/libsolidity/semanticTests/extracted/string_tuples.sol b/test/libsolidity/semanticTests/various/string_tuples.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/string_tuples.sol rename to test/libsolidity/semanticTests/various/string_tuples.sol diff --git a/test/libsolidity/semanticTests/extracted/super.sol b/test/libsolidity/semanticTests/various/super.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/super.sol rename to test/libsolidity/semanticTests/various/super.sol diff --git a/test/libsolidity/semanticTests/extracted/super_alone.sol b/test/libsolidity/semanticTests/various/super_alone.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/super_alone.sol rename to test/libsolidity/semanticTests/various/super_alone.sol diff --git a/test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol b/test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/swap_in_storage_overwrite.sol rename to test/libsolidity/semanticTests/various/swap_in_storage_overwrite.sol diff --git a/test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol b/test/libsolidity/semanticTests/various/test_underscore_in_hex.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/test_underscore_in_hex.sol rename to test/libsolidity/semanticTests/various/test_underscore_in_hex.sol diff --git a/test/libsolidity/semanticTests/extracted/tuples.sol b/test/libsolidity/semanticTests/various/tuples.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/tuples.sol rename to test/libsolidity/semanticTests/various/tuples.sol diff --git a/test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol b/test/libsolidity/semanticTests/various/typed_multi_variable_declaration.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/typed_multi_variable_declaration.sol rename to test/libsolidity/semanticTests/various/typed_multi_variable_declaration.sol diff --git a/test/libsolidity/semanticTests/extracted/value_complex.sol b/test/libsolidity/semanticTests/various/value_complex.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/value_complex.sol rename to test/libsolidity/semanticTests/various/value_complex.sol diff --git a/test/libsolidity/semanticTests/extracted/value_insane.sol b/test/libsolidity/semanticTests/various/value_insane.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/value_insane.sol rename to test/libsolidity/semanticTests/various/value_insane.sol diff --git a/test/libsolidity/semanticTests/extracted/write_storage_external.sol b/test/libsolidity/semanticTests/various/write_storage_external.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/write_storage_external.sol rename to test/libsolidity/semanticTests/various/write_storage_external.sol diff --git a/test/libsolidity/semanticTests/extracted/virtual_function_calls.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_calls.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/virtual_function_calls.sol rename to test/libsolidity/semanticTests/virtualFunctions/virtual_function_calls.sol diff --git a/test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol b/test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/virtual_function_usage_in_constructor_arguments.sol rename to test/libsolidity/semanticTests/virtualFunctions/virtual_function_usage_in_constructor_arguments.sol From 9544df34d70dc99f43819e957d5c2d1e2c527b5e Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 28 Feb 2020 12:48:59 +0100 Subject: [PATCH 091/165] solc fuzzers: Use compiler stack for fuzzing --- test/tools/afl_fuzzer.cpp | 2 +- test/tools/fuzzer_common.cpp | 101 +++++++++++++++------- test/tools/fuzzer_common.h | 3 +- test/tools/ossfuzz/solc_noopt_ossfuzz.cpp | 2 +- test/tools/ossfuzz/solc_opt_ossfuzz.cpp | 2 +- 5 files changed, 73 insertions(+), 37 deletions(-) diff --git a/test/tools/afl_fuzzer.cpp b/test/tools/afl_fuzzer.cpp index 1ca5428e1c30..eff4bc55afbb 100644 --- a/test/tools/afl_fuzzer.cpp +++ b/test/tools/afl_fuzzer.cpp @@ -124,7 +124,7 @@ Allowed options)", else if (arguments.count("standard-json")) FuzzerUtil::testStandardCompiler(input, quiet); else - FuzzerUtil::testCompiler(input, optimize, quiet); + FuzzerUtil::testCompilerJsonInterface(input, optimize, quiet); } catch (...) { diff --git a/test/tools/fuzzer_common.cpp b/test/tools/fuzzer_common.cpp index f66c2e841653..e4de0f185f38 100644 --- a/test/tools/fuzzer_common.cpp +++ b/test/tools/fuzzer_common.cpp @@ -17,28 +17,87 @@ #include +#include + #include + #include #include + #include +#include + #include using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::evmasm; - -static vector s_evmVersions = { - "homestead", - "tangerineWhistle", - "spuriousDragon", - "byzantium", - "constantinople", - "petersburg", - "istanbul" +using namespace solidity::langutil; + +static vector s_evmVersions = { + EVMVersion::homestead(), + EVMVersion::tangerineWhistle(), + EVMVersion::spuriousDragon(), + EVMVersion::byzantium(), + EVMVersion::constantinople(), + EVMVersion::petersburg(), + EVMVersion::istanbul(), + EVMVersion::berlin() }; +void FuzzerUtil::testCompilerJsonInterface(string const& _input, bool _optimize, bool _quiet) +{ + if (!_quiet) + cout << "Testing compiler " << (_optimize ? "with" : "without") << " optimizer." << endl; + + Json::Value config = Json::objectValue; + config["language"] = "Solidity"; + config["sources"] = Json::objectValue; + config["sources"][""] = Json::objectValue; + config["sources"][""]["content"] = _input; + config["settings"] = Json::objectValue; + config["settings"]["optimizer"] = Json::objectValue; + config["settings"]["optimizer"]["enabled"] = _optimize; + config["settings"]["optimizer"]["runs"] = 200; + config["settings"]["evmVersion"] = "berlin"; + + // Enable all SourceUnit-level outputs. + config["settings"]["outputSelection"]["*"][""][0] = "*"; + // Enable all Contract-level outputs. + config["settings"]["outputSelection"]["*"]["*"][0] = "*"; + + runCompiler(jsonCompactPrint(config), _quiet); +} + +void FuzzerUtil::testCompiler(string const& _input, bool _optimize) +{ + frontend::CompilerStack compiler; + EVMVersion evmVersion = s_evmVersions[_input.size() % s_evmVersions.size()]; + frontend::OptimiserSettings optimiserSettings; + if (_optimize) + optimiserSettings = frontend::OptimiserSettings::standard(); + else + optimiserSettings = frontend::OptimiserSettings::minimal(); + compiler.setSources({{"", _input}}); + compiler.setEVMVersion(evmVersion); + compiler.setOptimiserSettings(optimiserSettings); + try + { + compiler.compile(); + } + catch (Error const&) + { + } + catch (FatalError const&) + { + } + catch (UnimplementedFeatureError const&) + { + } +} + void FuzzerUtil::runCompiler(string const& _input, bool _quiet) { if (!_quiet) @@ -73,30 +132,6 @@ void FuzzerUtil::runCompiler(string const& _input, bool _quiet) } } -void FuzzerUtil::testCompiler(string const& _input, bool _optimize, bool _quiet) -{ - if (!_quiet) - cout << "Testing compiler " << (_optimize ? "with" : "without") << " optimizer." << endl; - - Json::Value config = Json::objectValue; - config["language"] = "Solidity"; - config["sources"] = Json::objectValue; - config["sources"][""] = Json::objectValue; - config["sources"][""]["content"] = _input; - config["settings"] = Json::objectValue; - config["settings"]["optimizer"] = Json::objectValue; - config["settings"]["optimizer"]["enabled"] = _optimize; - config["settings"]["optimizer"]["runs"] = 200; - config["settings"]["evmVersion"] = s_evmVersions[_input.size() % s_evmVersions.size()]; - - // Enable all SourceUnit-level outputs. - config["settings"]["outputSelection"]["*"][""][0] = "*"; - // Enable all Contract-level outputs. - config["settings"]["outputSelection"]["*"]["*"][0] = "*"; - - runCompiler(jsonCompactPrint(config), _quiet); -} - void FuzzerUtil::testConstantOptimizer(string const& _input, bool _quiet) { if (!_quiet) diff --git a/test/tools/fuzzer_common.h b/test/tools/fuzzer_common.h index edf196c1c81c..801c8c1c18bd 100644 --- a/test/tools/fuzzer_common.h +++ b/test/tools/fuzzer_common.h @@ -24,7 +24,8 @@ struct FuzzerUtil { static void runCompiler(std::string const& _input, bool _quiet); - static void testCompiler(std::string const& _input, bool _optimize, bool _quiet); + static void testCompilerJsonInterface(std::string const& _input, bool _optimize, bool _quiet); static void testConstantOptimizer(std::string const& _input, bool _quiet); static void testStandardCompiler(std::string const& _input, bool _quiet); + static void testCompiler(std::string const& _input, bool _optimize); }; diff --git a/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp b/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp index 3a2ac5f279ed..efed3769f58e 100644 --- a/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp @@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) if (_size <= 600) { string input(reinterpret_cast(_data), _size); - FuzzerUtil::testCompiler(input, /*optimize=*/false, /*quiet=*/true); + FuzzerUtil::testCompiler(input, /*optimize=*/false); } return 0; } diff --git a/test/tools/ossfuzz/solc_opt_ossfuzz.cpp b/test/tools/ossfuzz/solc_opt_ossfuzz.cpp index 72a59cba40eb..fc431ffe56d0 100644 --- a/test/tools/ossfuzz/solc_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_opt_ossfuzz.cpp @@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) if (_size <= 600) { string input(reinterpret_cast(_data), _size); - FuzzerUtil::testCompiler(input, /*optimize=*/true, /*quiet=*/true); + FuzzerUtil::testCompiler(input, /*optimize=*/true); } return 0; } From 0fcb1427c9bd8d25227b6bd5682c97d36144fe83 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Fri, 20 Mar 2020 17:52:51 +0100 Subject: [PATCH 092/165] Fix Yul codegen when dynamic array is used as rhs of assignment --- .../codegen/ir/IRGeneratorForStatements.cpp | 2 +- .../viaYul/array_2d_assignment.sol | 14 ++++++++++++++ .../semanticTests/viaYul/array_2d_new.sol | 12 ++++++++++++ .../viaYul/array_3d_assignment.sol | 19 +++++++++++++++++++ .../semanticTests/viaYul/array_3d_new.sol | 16 ++++++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_2d_new.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_3d_new.sol diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 21a105db5c6f..1d40c35b1970 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1588,7 +1588,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable solAssert(dynamic_cast(&_lvalue.type), ""); auto const* valueReferenceType = dynamic_cast(&_value.type()); solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), ""); - m_code << "mstore(" + _memory.address + ", " + _value.name() + ")\n"; + m_code << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; } }, [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, diff --git a/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol b/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol new file mode 100644 index 000000000000..ff9c03cbe857 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_2d_assignment.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][] memory a = new uint[][](2); + for (uint i = 0; i < 2; ++i) + a[i] = new uint[](3); + a[1][1] = n; + uint[] memory b = a[1]; + return b[1]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_2d_new.sol b/test/libsolidity/semanticTests/viaYul/array_2d_new.sol new file mode 100644 index 000000000000..bfc8b201363c --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_2d_new.sol @@ -0,0 +1,12 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][] memory a = new uint[][](2); + for (uint i = 0; i < 2; ++i) + a[i] = new uint[](3); + return a[0][0] = n; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol b/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol new file mode 100644 index 000000000000..a2b3de54f66c --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_3d_assignment.sol @@ -0,0 +1,19 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][][] memory a = new uint[][][](2); + for (uint i = 0; i < 2; ++i) + { + a[i] = new uint[][](3); + for (uint j = 0; j < 3; ++j) + a[i][j] = new uint[](4); + } + a[1][1][1] = n; + uint[][] memory b = a[1]; + uint[] memory c = b[1]; + return c[1]; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 diff --git a/test/libsolidity/semanticTests/viaYul/array_3d_new.sol b/test/libsolidity/semanticTests/viaYul/array_3d_new.sol new file mode 100644 index 000000000000..c3ff22ca351f --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_3d_new.sol @@ -0,0 +1,16 @@ +contract C { + function f(uint n) public pure returns (uint) { + uint[][][] memory a = new uint[][][](2); + for (uint i = 0; i < 2; ++i) + { + a[i] = new uint[][](3); + for (uint j = 0; j < 3; ++j) + a[i][j] = new uint[](4); + } + return a[1][1][1] = n; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 42 -> 42 From cae4b7dd0e5b65289ccbac767cec48ff431d399c Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Sun, 22 Mar 2020 17:15:44 +0400 Subject: [PATCH 093/165] fix typo in docstring error message --- libsolidity/analysis/DocStringAnalyser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index e802c4204638..ee0a39163704 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -153,7 +153,7 @@ void DocStringAnalyser::parseDocStrings( appendError( _node.documentation()->location(), "Documentation tag \"@" + docTag.first + " " + docTag.second.content + "\"" + - " exceedes the number of return parameters." + " exceeds the number of return parameters." ); else { From a7d6128a8ef9359678816c0ed1063a383c74d4c8 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sun, 22 Mar 2020 22:23:29 +0100 Subject: [PATCH 094/165] Improved `.clang_format` file. --- .clang-format | 13 +++++++++++-- CODING_STYLE.md | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.clang-format b/.clang-format index f9953c17b346..edd5de4d26bc 100644 --- a/.clang-format +++ b/.clang-format @@ -6,26 +6,35 @@ # Note that clang-format cannot express the style that closing parentheses # behave similar to closing curly braces in a multi-line setting in that # they have to be on a line of their own at the same indentation level -# as the opening part. +# as the opening part (aka "dangling parenthesis", see https://reviews.llvm.org/D33029). Language: Cpp BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak AlignEscapedNewlinesLeft: true AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BreakBeforeBinaryOperators: All BreakBeforeBraces: Allman ColumnLimit: 120 ContinuationIndentWidth: 4 +FixNamespaceComments: false IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 2 PenaltyBreakBeforeFirstCallParameter: 2000 +PointerAlignment: Left SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeCtorInitializerColon: false +SpaceBeforeInheritanceColon: false SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false TabWidth: 4 -UseTab: ForIndentation +UseTab: Always # Local Variables: # mode: yaml diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 6bdb48fba502..78b2ab310312 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -141,7 +141,7 @@ struct MeanSigma double const d = 0; int i = 0; int j = 0; -char* s; +char* s = nullptr; MeanAndSigma ms meanAndSigma(std::vector const& _v, Accuracy _a); Derived* x = dynamic_cast(base); for (auto i = x->begin(); i != x->end(); ++i) {} From fe659ceb4103490efce74e4653b65321e729cea8 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 13 Mar 2020 12:50:14 +0100 Subject: [PATCH 095/165] Anything outside storage is always a pointer. --- Changelog.md | 2 ++ libsolidity/ast/Types.cpp | 18 ++++++++++--- libsolidity/ast/Types.h | 4 ++- .../ASTJSON/short_type_name_ref.json | 2 +- test/libsolidity/gasTests/abiv2.sol | 6 ++--- ...ublic_state_overridding_dynamic_struct.sol | 24 +++++++++++++++++ ..._overridding_mapping_to_dynamic_struct.sol | 26 +++++++++++++++++++ ...var_override_mapping_to_dynamic_struct.sol | 12 +++++++++ ...ar_override_struct_with_memory_element.sol | 13 ++++++++++ 9 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol create mode 100644 test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol diff --git a/Changelog.md b/Changelog.md index 9c2d9a384e88..2472d946712a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,8 @@ Compiler Features: Bugfixes: * Inline Assembly: Fix internal error when accessing incorrect constant variables. + * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. + * JSON AST: Always add pointer suffix for memory reference types. ### 0.6.4 (2020-03-10) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d760e08102e7..9ed35e694fce 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1487,11 +1487,19 @@ TypeResult ReferenceType::unaryOperatorResult(Token _operator) const case DataLocation::Memory: return TypeProvider::emptyTuple(); case DataLocation::Storage: - return m_isPointer ? nullptr : TypeProvider::emptyTuple(); + return isPointer() ? nullptr : TypeProvider::emptyTuple(); } return nullptr; } +bool ReferenceType::isPointer() const +{ + if (m_location == DataLocation::Storage) + return m_isPointer; + else + return true; +} + TypePointer ReferenceType::copyForLocationIfReference(Type const* _type) const { return TypeProvider::withLocationIfReference(m_location, _type); @@ -1502,7 +1510,7 @@ string ReferenceType::stringForReferencePart() const switch (m_location) { case DataLocation::Storage: - return string("storage ") + (m_isPointer ? "pointer" : "ref"); + return string("storage ") + (isPointer() ? "pointer" : "ref"); case DataLocation::CallData: return "calldata"; case DataLocation::Memory: @@ -1868,7 +1876,8 @@ u256 ArrayType::memoryDataSize() const std::unique_ptr ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(_location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; copy->m_arrayKind = m_arrayKind; copy->m_baseType = copy->copyForLocationIfReference(m_baseType); copy->m_hasDynamicLength = m_hasDynamicLength; @@ -2247,7 +2256,8 @@ TypeResult StructType::interfaceType(bool _inLibrary) const std::unique_ptr StructType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(m_struct, _location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; return copy; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 5aada86c3a5f..73943b18ade6 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -701,7 +701,9 @@ class ReferenceType: public Type /// pointer type, state variables are bound references. Assignments to pointers or deleting /// them will not modify storage (that will only change the pointer). Assignment from /// non-storage objects to a variable of storage pointer type is not possible. - bool isPointer() const { return m_isPointer; } + /// For anything other than storage, this always returns true because assignments + /// never change the contents of the original value. + bool isPointer() const; bool operator==(ReferenceType const& _other) const { diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index 0aa3d298440a..501184c9c4d1 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -54,7 +54,7 @@ "storageLocation": "memory", "typeDescriptions": { - "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_$dyn_memory_ptr", + "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr", "typeString": "uint256[][]" }, "typeName": diff --git a/test/libsolidity/gasTests/abiv2.sol b/test/libsolidity/gasTests/abiv2.sol index f0892b83b5a6..1fd96ff7603a 100644 --- a/test/libsolidity/gasTests/abiv2.sol +++ b/test/libsolidity/gasTests/abiv2.sol @@ -14,9 +14,9 @@ contract C { } // ---- // creation: -// codeDepositCost: 1120000 -// executionCost: 1160 -// totalCost: 1121160 +// codeDepositCost: 1094400 +// executionCost: 1134 +// totalCost: 1095534 // external: // a(): 1130 // b(uint256): infinite diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol new file mode 100644 index 000000000000..f6fa4d45e77a --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test() external virtual returns (uint256 v, string memory s) + { + v = 42; + s = "test"; + } +} +contract X is A +{ + S public override test; + + function set() public { test.v = 2; test.s = "statevar"; } +} + + +// ---- +// test() -> 0, 64, 0 +// set() -> +// test() -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000000..404013ee6c6a --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test(uint256 x) external virtual returns (uint256 v, string memory s) + { + v = x; + s = "test"; + } +} +contract X is A +{ + mapping(uint256 => S) public override test; + + function set() public { test[42].v = 2; test[42].s = "statevar"; } +} + + +// ---- +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 0, 64, 0 +// set() -> +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000000..d02284aeff95 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol @@ -0,0 +1,12 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + function f(address x) external virtual returns (uint256, string memory); +} +contract D is C { + mapping(address => S) public override f; +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol new file mode 100644 index 000000000000..4e6e02598729 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + + function f() external virtual returns (uint256, string memory); +} +contract D is C { + S public override f; +} From 7107ef13a7a3cd65cb805645f8e445fe692145bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 11 Mar 2020 21:15:12 +0100 Subject: [PATCH 096/165] [yul-phaser] Program: Add parseObject() --- tools/yulPhaser/Program.cpp | 41 +++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Program.h | 4 ++++ 2 files changed, 45 insertions(+) diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index c397cd1f49b0..7dcfddd79b2e 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,46 @@ variant, ErrorList> Program::parseSource(Dialect const& _diale return variant, ErrorList>(move(ast)); } +variant, ErrorList> Program::parseObject(Dialect const& _dialect, CharStream _source) +{ + ErrorList errors; + ErrorReporter errorReporter(errors); + auto scanner = make_shared(move(_source)); + + ObjectParser parser(errorReporter, _dialect); + shared_ptr object = parser.parse(scanner, false); + if (object == nullptr || !errorReporter.errors().empty()) + // NOTE: It's possible to get errors even if the returned object is non-null. + // For example when there are errors in a nested object. + return errors; + + Object* deployedObject = nullptr; + if (object->subObjects.size() > 0) + for (auto& subObject: object->subObjects) + // solc --ir produces an object with a subobject of the same name as the outer object + // but suffixed with "_deployed". + // The other object references the nested one which makes analysis fail. Below we try to + // extract just the nested one for that reason. This is just a heuristic. If there's no + // subobject with such a suffix we fall back to accepting the whole object as is. + if (subObject != nullptr && subObject->name.str() == object->name.str() + "_deployed") + { + deployedObject = dynamic_cast(subObject.get()); + if (deployedObject != nullptr) + break; + } + Object* selectedObject = (deployedObject != nullptr ? deployedObject : object.get()); + + // NOTE: I'm making a copy of the whole AST to get unique_ptr rather than shared_ptr. + // This is a slight performance hit but it's much less than the parsing itself. + // unique_ptr lets me be sure that two Program instances can never share the AST by mistake. + // The public API of the class does not provide access to the smart pointer so it won't be hard + // to switch to shared_ptr if the copying turns out to be an issue (though it would be better + // to refactor ObjectParser and Object to use unique_ptr instead). + auto astCopy = make_unique(get(ASTCopier{}(*selectedObject->code))); + + return variant, ErrorList>(move(astCopy)); +} + variant, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) { ErrorList errors; diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index 6da9751b9647..df44f2ba4ddc 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -98,6 +98,10 @@ class Program yul::Dialect const& _dialect, langutil::CharStream _source ); + static std::variant, langutil::ErrorList> parseObject( + yul::Dialect const& _dialect, + langutil::CharStream _source + ); static std::variant, langutil::ErrorList> analyzeAST( yul::Dialect const& _dialect, yul::Block const& _ast From 29186f9951097a262ad97f0eba5afd2b07f911c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 11 Mar 2020 21:16:01 +0100 Subject: [PATCH 097/165] [yul-phaser] Program: Switch from using parseCode() to parseObject() --- test/yulPhaser/Program.cpp | 126 ++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Program.cpp | 17 +---- tools/yulPhaser/Program.h | 4 -- 3 files changed, 127 insertions(+), 20 deletions(-) diff --git a/test/yulPhaser/Program.cpp b/test/yulPhaser/Program.cpp index 5d4e012f39a8..e69f0fc5c654 100644 --- a/test/yulPhaser/Program.cpp +++ b/test/yulPhaser/Program.cpp @@ -189,6 +189,132 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyze BOOST_TEST(holds_alternative(Program::load(sourceStream))); } +BOOST_AUTO_TEST_CASE(load_should_accept_yul_objects_as_input) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " mstore(64, 128)\n" + " if iszero(calldatasize()) {}\n" + " revert(0, 0)\n" + " }\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); +} + +BOOST_AUTO_TEST_CASE(load_should_return_errors_if_analysis_of_object_code_fails) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " return(0, datasize(\"C_178_deployed\"))\n" + " }\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); +} + +BOOST_AUTO_TEST_CASE(load_should_return_errors_if_parsing_of_nested_object_fails) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " return(0, datasize(\"C_178_deployed\"))\n" + " }\n" + " object \"duplicate_name\" {\n" + " code {\n" + " mstore(64, 128)\n" + " }\n" + " }\n" + " object \"duplicate_name\" {\n" + " code {\n" + " mstore(64, 128)\n" + " }\n" + " }\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); +} + +BOOST_AUTO_TEST_CASE(load_should_extract_nested_object_with_deployed_suffix_if_present) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " return(0, datasize(\"C_178_deployed\"))\n" + " }\n" + " object \"C_178_deployed\" {\n" + " code {\n" + " mstore(64, 128)\n" + " if iszero(calldatasize()) {}\n" + " revert(0, 0)\n" + " }\n" + " }\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); +} + +BOOST_AUTO_TEST_CASE(load_should_fall_back_to_parsing_the_whole_object_if_there_is_no_subobject_with_the_right_name) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " mstore(64, 128)\n" + " }\n" + " object \"subobject\" {\n" + " code {\n" + " if iszero(calldatasize()) {}\n" + " revert(0, 0)\n" + " }\n" + " }\n" + " object \"C_177_deployed\" {\n" + " code {\n" + " if iszero(calldatasize()) {}\n" + " revert(0, 0)\n" + " }\n" + " }\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); + + Block const& parentBlock = skipRedundantBlocks(get(programOrErrors).ast()); + BOOST_TEST(parentBlock.statements.size() == 1); + BOOST_TEST(holds_alternative(parentBlock.statements[0])); +} + +BOOST_AUTO_TEST_CASE(load_should_ignore_data_in_objects) +{ + string sourceCode( + "object \"C_178\" {\n" + " code {\n" + " mstore(64, 128)\n" + " }\n" + " data \"C_178_deployed\" hex\"4123\"\n" + "}\n" + ); + CharStream sourceStream(sourceCode, current_test_case().p_name); + auto programOrErrors = Program::load(sourceStream); + + BOOST_TEST(holds_alternative(programOrErrors)); +} + BOOST_AUTO_TEST_CASE(optimise) { string sourceCode( diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index 7dcfddd79b2e..a457750d2227 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -78,7 +78,7 @@ variant Program::load(CharStream& _sourceCode) // ASSUMPTION: parseSource() rewinds the stream on its own Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); - variant, ErrorList> astOrErrors = parseSource(dialect, _sourceCode); + variant, ErrorList> astOrErrors = parseObject(dialect, _sourceCode); if (holds_alternative(astOrErrors)) return get(astOrErrors); @@ -122,21 +122,6 @@ string Program::toJson() const return jsonPrettyPrint(serializedAst); } -variant, ErrorList> Program::parseSource(Dialect const& _dialect, CharStream _source) -{ - ErrorList errors; - ErrorReporter errorReporter(errors); - auto scanner = make_shared(move(_source)); - Parser parser(errorReporter, _dialect); - - unique_ptr ast = parser.parse(scanner, false); - if (ast == nullptr) - return errors; - - assert(errorReporter.errors().empty()); - return variant, ErrorList>(move(ast)); -} - variant, ErrorList> Program::parseObject(Dialect const& _dialect, CharStream _source) { ErrorList errors; diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index df44f2ba4ddc..10fed6de2f58 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -94,10 +94,6 @@ class Program m_nameDispenser(_dialect, *m_ast, {}) {} - static std::variant, langutil::ErrorList> parseSource( - yul::Dialect const& _dialect, - langutil::CharStream _source - ); static std::variant, langutil::ErrorList> parseObject( yul::Dialect const& _dialect, langutil::CharStream _source From a66ceb11c683d1a2cc1c62f028163ca3e9e2305e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 20 Mar 2020 17:44:34 +0100 Subject: [PATCH 098/165] [yul-phaser] Add --prefix option --- test/yulPhaser/Phaser.cpp | 38 +++++++++++++++++++++++++++++++++----- tools/yulPhaser/Phaser.cpp | 15 +++++++++++++++ tools/yulPhaser/Phaser.h | 1 + 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index aab34db61734..04dfbe3dcb42 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -324,11 +324,14 @@ BOOST_AUTO_TEST_CASE(build_should_load_programs_from_files) { TemporaryDirectory tempDir; vector sources{"{}", "{{}}", "{{{}}}"}; - ProgramFactory::Options options{/* inputFiles = */ { - tempDir.memberPath("program1.yul"), - tempDir.memberPath("program2.yul"), - tempDir.memberPath("program3.yul"), - }}; + ProgramFactory::Options options{ + /* inputFiles = */ { + tempDir.memberPath("program1.yul"), + tempDir.memberPath("program2.yul"), + tempDir.memberPath("program3.yul"), + }, + /* prefix = */ "", + }; for (size_t i = 0; i < sources.size(); ++i) { @@ -346,6 +349,31 @@ BOOST_AUTO_TEST_CASE(build_should_load_programs_from_files) } } +BOOST_AUTO_TEST_CASE(build_should_apply_prefix) +{ + TemporaryDirectory tempDir; + ProgramFactory::Options options{ + /* inputFiles = */ {tempDir.memberPath("program1.yul")}, + /* prefix = */ "f", + }; + + CharStream nestedSource("{{{let x:= 1}}}", ""); + Program nestedProgram = get(Program::load(nestedSource)); + Program flatProgram = get(Program::load(nestedSource)); + flatProgram.optimise(Chromosome("f").optimisationSteps()); + assert(toString(nestedProgram) != toString(flatProgram)); + + { + ofstream tmpFile(options.inputFiles[0]); + tmpFile << nestedSource.source() << endl; + } + + vector programs = ProgramFactory::build(options); + + BOOST_TEST(programs.size() == 1); + BOOST_TEST(toString(programs[0]) == toString(flatProgram)); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index da0296eff0a8..b29938f22f4e 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -285,6 +285,7 @@ ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_m { return { _arguments["input-files"].as>(), + _arguments["prefix"].as(), }; } @@ -300,6 +301,8 @@ vector ProgramFactory::build(Options const& _options) cerr << get(programOrErrors) << endl; assertThrow(false, InvalidProgram, "Failed to load program " + path); } + + get(programOrErrors).optimise(Chromosome(_options.prefix).optimisationSteps()); inputPrograms.push_back(move(get(programOrErrors))); } @@ -348,6 +351,18 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() generalDescription.add_options() ("help", "Show help message and exit.") ("input-files", po::value>()->required()->value_name(""), "Input files.") + ( + "prefix", + po::value()->value_name("")->default_value(""), + "Initial optimisation steps automatically applied to every input program.\n" + "The result is treated as if it was the actual input, i.e. the steps are not considered " + "a part of the chromosomes and cannot be mutated. The values of relative metric values " + "are also relative to the fitness of a program with these steps applied rather than the " + "fitness of the original program.\n" + "Note that phaser always adds a 'hgo' prefix to ensure that chromosomes can " + "contain arbitrary optimisation steps. This implicit prefix cannot be changed or " + "or removed using this option. The value given here is applied after it." + ) ("seed", po::value()->value_name(""), "Seed for the random number generator.") ( "rounds", diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 2e72c31f661e..9814c9111f3b 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -169,6 +169,7 @@ class ProgramFactory struct Options { std::vector inputFiles; + std::string prefix; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; From 0e66e07e5ca6af283cf63487f7d413b3e226a47c Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Wed, 11 Mar 2020 13:03:57 +0100 Subject: [PATCH 099/165] Add antlr-based grammar and test it. --- .circleci/config.yml | 13 + docs/Solidity.g4 | 482 ++++++++++++++++++++++++++++++++++ scripts/test_antlr_grammar.sh | 101 +++++++ 3 files changed, 596 insertions(+) create mode 100644 docs/Solidity.g4 create mode 100755 scripts/test_antlr_grammar.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 6115f364435e..ac1dda7dd0c9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -307,6 +307,18 @@ jobs: name: Linting Python Scripts command: ./scripts/pylint_all.py + chk_antlr_grammar: + docker: + - image: buildpack-deps:eoan + steps: + - checkout + - run: + name: Install Java + command: apt -q update && apt install -y openjdk-14-jdk + - run: + name: Run tests + command: ./scripts/test_antlr_grammar.sh + chk_buglist: docker: - image: circleci/node @@ -773,6 +785,7 @@ workflows: - chk_buglist: *workflow_trigger_on_tags - chk_proofs: *workflow_trigger_on_tags - chk_pylint: *workflow_trigger_on_tags + - chk_antlr_grammar: *workflow_trigger_on_tags # build-only - b_docs: *workflow_trigger_on_tags diff --git a/docs/Solidity.g4 b/docs/Solidity.g4 new file mode 100644 index 000000000000..8721f47a4dd8 --- /dev/null +++ b/docs/Solidity.g4 @@ -0,0 +1,482 @@ +// Copyright 2020 Gonçalo Sá +// Copyright 2016-2019 Federico Bond +// Licensed under the MIT license. See LICENSE file in the project root for details. + +// This grammar is much less strict than what Solidity currently parses +// to allow this to pass with older versions of Solidity. + +grammar Solidity; + +sourceUnit + : (pragmaDirective | importDirective | structDefinition | enumDefinition | contractDefinition)* EOF ; + +pragmaDirective + : 'pragma' pragmaName pragmaValue ';' ; + +pragmaName + : identifier ; + +pragmaValue + : version | expression ; + +version + : versionConstraint versionConstraint? ; + +versionConstraint + : versionOperator? VersionLiteral ; + +versionOperator + : '^' | '~' | '>=' | '>' | '<' | '<=' | '=' ; + +importDirective + : 'import' StringLiteralFragment ('as' identifier)? ';' + | 'import' ('*' | identifier) ('as' identifier)? 'from' StringLiteralFragment ';' + | 'import' '{' importDeclaration ( ',' importDeclaration )* '}' 'from' StringLiteralFragment ';' ; + +importDeclaration + : identifier ('as' identifier)? ; + +contractDefinition + : 'abstract'? ( 'contract' | 'interface' | 'library' ) identifier + ( 'is' inheritanceSpecifier (',' inheritanceSpecifier )* )? + '{' contractPart* '}' ; + +inheritanceSpecifier + : userDefinedTypeName ( '(' expressionList? ')' )? ; + +contractPart + : stateVariableDeclaration + | usingForDeclaration + | structDefinition + | modifierDefinition + | functionDefinition + | eventDefinition + | enumDefinition ; + +stateVariableDeclaration + : typeName + ( PublicKeyword | InternalKeyword | PrivateKeyword | ConstantKeyword | ImmutableKeyword | overrideSpecifier )* + identifier ('=' expression)? ';' ; + +overrideSpecifier : 'override' ( '(' userDefinedTypeName (',' userDefinedTypeName)* ')' )? ; + +usingForDeclaration + : 'using' identifier 'for' ('*' | typeName) ';' ; + +structDefinition + : 'struct' identifier + '{' ( variableDeclaration ';' (variableDeclaration ';')* )? '}' ; + +modifierDefinition + : 'modifier' identifier parameterList? ( VirtualKeyword | overrideSpecifier )* block ; + +functionDefinition + : functionDescriptor parameterList modifierList returnParameters? ( ';' | block ) ; + +functionDescriptor + : 'function' ( identifier | ReceiveKeyword | FallbackKeyword )? + | ConstructorKeyword + | FallbackKeyword + | ReceiveKeyword ; + +returnParameters + : 'returns' parameterList ; + +modifierList + : ( modifierInvocation | stateMutability | ExternalKeyword + | PublicKeyword | InternalKeyword | PrivateKeyword | VirtualKeyword | overrideSpecifier )* ; + +modifierInvocation + : identifier ( '(' expressionList? ')' )? ; + +eventDefinition + : 'event' identifier eventParameterList AnonymousKeyword? ';' ; + +enumDefinition + : 'enum' identifier '{' enumValue? (',' enumValue)* '}' ; + +enumValue + : identifier ; + +parameterList + : '(' ( parameter (',' parameter)* )? ')' ; + +parameter + : typeName storageLocation? identifier? ; + +eventParameterList + : '(' ( eventParameter (',' eventParameter)* )? ')' ; + +eventParameter + : typeName IndexedKeyword? identifier? ; + +variableDeclaration + : typeName storageLocation? identifier ; + +typeName + : elementaryTypeName + | userDefinedTypeName + | mapping + | typeName '[' expression? ']' + | functionTypeName ; + +userDefinedTypeName + : identifier ( '.' identifier )* ; + +mapping + : 'mapping' '(' (elementaryTypeName | userDefinedTypeName) '=>' typeName ')' ; + +functionTypeName + : 'function' parameterList modifierList returnParameters? ; + +storageLocation + : 'memory' | 'storage' | 'calldata'; + +stateMutability + : PureKeyword | ConstantKeyword | ViewKeyword | PayableKeyword ; + +block + : '{' statement* '}' ; + +statement + : ifStatement + | tryStatement + | whileStatement + | forStatement + | block + | inlineAssemblyStatement + | doWhileStatement + | continueStatement + | breakStatement + | returnStatement + | throwStatement + | emitStatement + | simpleStatement ; + +expressionStatement + : expression ';' ; + +ifStatement + : 'if' '(' expression ')' statement ( 'else' statement )? ; + +tryStatement : 'try' expression returnParameters? block catchClause+ ; + +// In reality catch clauses still are not processed as below +// the identifier can only be a set string: "Error". But plans +// of the Solidity team include possible expansion so we'll +// leave this as is, befitting with the Solidity docs. +catchClause : 'catch' ( identifier? parameterList )? block ; + +whileStatement + : 'while' '(' expression ')' statement ; + +forStatement + : 'for' '(' ( simpleStatement | ';' ) ( expressionStatement | ';' ) expression? ')' statement ; + +simpleStatement + : ( variableDeclarationStatement | expressionStatement ) ; + +inlineAssemblyStatement + : 'assembly' StringLiteralFragment? assemblyBlock ; + +doWhileStatement + : 'do' statement 'while' '(' expression ')' ';' ; + +continueStatement + : 'continue' ';' ; + +breakStatement + : 'break' ';' ; + +returnStatement + : 'return' expression? ';' ; + +// throw is no longer supported by latest Solidity. +throwStatement + : 'throw' ';' ; + +emitStatement + : 'emit' functionCall ';' ; + +// 'var' is no longer supported by latest Solidity. +variableDeclarationStatement + : ( 'var' identifierList | variableDeclaration | '(' variableDeclarationList ')' ) ( '=' expression )? ';'; + +variableDeclarationList + : variableDeclaration? (',' variableDeclaration? )* ; + +identifierList + : '(' ( identifier? ',' )* identifier? ')' ; + +elementaryTypeName + : 'address' PayableKeyword? | 'bool' | 'string' | 'var' | Int | Uint | 'byte' | Byte | Fixed | Ufixed ; + +Int + : 'int' | 'int8' | 'int16' | 'int24' | 'int32' | 'int40' | 'int48' | 'int56' | 'int64' | 'int72' | 'int80' | 'int88' | 'int96' | 'int104' | 'int112' | 'int120' | 'int128' | 'int136' | 'int144' | 'int152' | 'int160' | 'int168' | 'int176' | 'int184' | 'int192' | 'int200' | 'int208' | 'int216' | 'int224' | 'int232' | 'int240' | 'int248' | 'int256' ; + +Uint + : 'uint' | 'uint8' | 'uint16' | 'uint24' | 'uint32' | 'uint40' | 'uint48' | 'uint56' | 'uint64' | 'uint72' | 'uint80' | 'uint88' | 'uint96' | 'uint104' | 'uint112' | 'uint120' | 'uint128' | 'uint136' | 'uint144' | 'uint152' | 'uint160' | 'uint168' | 'uint176' | 'uint184' | 'uint192' | 'uint200' | 'uint208' | 'uint216' | 'uint224' | 'uint232' | 'uint240' | 'uint248' | 'uint256' ; + +Byte + : 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' | 'bytes6' | 'bytes7' | 'bytes8' | 'bytes9' | 'bytes10' | 'bytes11' | 'bytes12' | 'bytes13' | 'bytes14' | 'bytes15' | 'bytes16' | 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32' ; + +Fixed + : 'fixed' | ( 'fixed' [0-9]+ 'x' [0-9]+ ) ; + +Ufixed + : 'ufixed' | ( 'ufixed' [0-9]+ 'x' [0-9]+ ) ; + +expression + : expression ('++' | '--') + | 'new' typeName + | expression '[' expression? ']' + | expression '[' expression? ':' expression? ']' + | expression '.' identifier + | expression '{' nameValueList '}' + | expression '(' functionCallArguments ')' + | PayableKeyword '(' expression ')' + | '(' expression ')' + | ('++' | '--') expression + | ('+' | '-') expression + | ('after' | 'delete') expression + | '!' expression + | '~' expression + | expression '**' expression + | expression ('*' | '/' | '%') expression + | expression ('+' | '-') expression + | expression ('<<' | '>>') expression + | expression '&' expression + | expression '^' expression + | expression '|' expression + | expression ('<' | '>' | '<=' | '>=') expression + | expression ('==' | '!=') expression + | expression '&&' expression + | expression '||' expression + | expression '?' expression ':' expression + | expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') expression + | primaryExpression ; + +primaryExpression + : BooleanLiteral + | numberLiteral + | hexLiteral + | stringLiteral + | identifier ('[' ']')? + | TypeKeyword + | tupleExpression + | typeNameExpression ('[' ']')? ; + +expressionList + : expression (',' expression)* ; + +nameValueList + : nameValue (',' nameValue)* ','? ; + +nameValue + : identifier ':' expression ; + +functionCallArguments + : '{' nameValueList? '}' + | expressionList? ; + +functionCall + : expression '(' functionCallArguments ')' ; + +tupleExpression + : '(' ( expression? ( ',' expression? )* ) ')' + | '[' ( expression ( ',' expression )* )? ']' ; + +typeNameExpression + : elementaryTypeName + | userDefinedTypeName ; + +assemblyItem + : identifier + | assemblyBlock + | assemblyExpression + | assemblyLocalDefinition + | assemblyAssignment + | assemblyStackAssignment + | labelDefinition + | assemblySwitch + | assemblyFunctionDefinition + | assemblyFor + | assemblyIf + | BreakKeyword + | ContinueKeyword + | LeaveKeyword + | subAssembly + | numberLiteral + | stringLiteral + | hexLiteral ; + +assemblyBlock + : '{' assemblyItem* '}' ; + +assemblyExpression + : assemblyCall | assemblyLiteral ; + +assemblyCall + : ( 'return' | 'address' | 'byte' | identifier ) ( '(' assemblyExpression? ( ',' assemblyExpression )* ')' )? ; + +assemblyLocalDefinition + : 'let' assemblyIdentifierList ( ':=' assemblyExpression )? ; + +assemblyAssignment + : assemblyIdentifierList ':=' assemblyExpression ; + +assemblyIdentifierList + : identifier ( ',' identifier )* ; + +assemblyStackAssignment + : '=:' identifier ; + +labelDefinition + : identifier ':' ; + +assemblySwitch + : 'switch' assemblyExpression assemblyCase* ; + +assemblyCase + : 'case' assemblyLiteral assemblyType? assemblyBlock + | 'default' assemblyBlock ; + +assemblyFunctionDefinition + : 'function' identifier '(' assemblyTypedVariableList? ')' + assemblyFunctionReturns? assemblyBlock ; + +assemblyFunctionReturns + : ( '-' '>' assemblyTypedVariableList ) ; + +assemblyFor + : 'for' assemblyBlock assemblyExpression assemblyBlock assemblyBlock ; + +assemblyIf + : 'if' assemblyExpression assemblyBlock ; + +assemblyLiteral + : ( stringLiteral | DecimalNumber | HexNumber | hexLiteral | BooleanLiteral ) assemblyType? ; + +assemblyTypedVariableList + : identifier assemblyType? ( ',' assemblyTypedVariableList )? ; + +assemblyType + : ':' identifier ; + +subAssembly + : 'assembly' identifier assemblyBlock ; + +numberLiteral + : (DecimalNumber | HexNumber) NumberUnit? ; + +identifier + : ('from' | 'calldata' | 'address' | Identifier) ; + +BooleanLiteral + : 'true' | 'false' ; + +DecimalNumber + : ( DecimalDigits | (DecimalDigits? '.' DecimalDigits) ) ( [eE] '-'? DecimalDigits )? ; + +fragment +DecimalDigits + : [0-9] ( '_'? [0-9] )* ; + +HexNumber + : '0' [xX] HexDigits ; + +fragment +HexDigits + : HexCharacter ( '_'? HexCharacter )* ; + +NumberUnit + : 'wei' | 'szabo' | 'finney' | 'ether' + | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ; + +HexLiteralFragment + : 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ; + +hexLiteral : HexLiteralFragment+ ; + +fragment +HexPair + : HexCharacter HexCharacter ; + +fragment +HexCharacter + : [0-9A-Fa-f] ; + +ReservedKeyword + : 'after' + | 'case' + | 'default' + | 'final' + | 'in' + | 'inline' + | 'let' + | 'match' + | 'null' + | 'of' + | 'relocatable' + | 'static' + | 'switch' + | 'typeof' ; + +AnonymousKeyword : 'anonymous' ; +BreakKeyword : 'break' ; +ConstantKeyword : 'constant' ; +ImmutableKeyword : 'immutable' ; +ContinueKeyword : 'continue' ; +LeaveKeyword : 'leave' ; +ExternalKeyword : 'external' ; +IndexedKeyword : 'indexed' ; +InternalKeyword : 'internal' ; +PayableKeyword : 'payable' ; +PrivateKeyword : 'private' ; +PublicKeyword : 'public' ; +VirtualKeyword : 'virtual' ; +PureKeyword : 'pure' ; +TypeKeyword : 'type' ; +ViewKeyword : 'view' ; + +ConstructorKeyword : 'constructor' ; +FallbackKeyword : 'fallback' ; +ReceiveKeyword : 'receive' ; + +Identifier + : IdentifierStart IdentifierPart* ; + +fragment +IdentifierStart + : [a-zA-Z$_] ; + +fragment +IdentifierPart + : [a-zA-Z0-9$_] ; + +stringLiteral + : StringLiteralFragment+ ; + +StringLiteralFragment + : '"' DoubleQuotedStringCharacter* '"' + | '\'' SingleQuotedStringCharacter* '\'' ; + +fragment +DoubleQuotedStringCharacter + : ~["\r\n\\] | ('\\' .) ; + +fragment +SingleQuotedStringCharacter + : ~['\r\n\\] | ('\\' .) ; + +VersionLiteral + : [0-9]+ '.' [0-9]+ ('.' [0-9]+)? ; + +WS + : [ \t\r\n\u000C]+ -> skip ; + +COMMENT + : '/*' .*? '*/' -> channel(HIDDEN) ; + +LINE_COMMENT + : '//' ~[\r\n]* -> channel(HIDDEN) ; diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh new file mode 100755 index 000000000000..97cbe4ab415d --- /dev/null +++ b/scripts/test_antlr_grammar.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +set -e + +ROOT_DIR="$(dirname "$0")"/.. +WORKDIR="${ROOT_DIR}/build/antlr" +ANTLR_JAR="${ROOT_DIR}/build/deps/antlr4.jar" +ANTLR_JAR_URI="https://www.antlr.org/download/antlr-4.7.2-complete.jar" +GRAMMAR_FILE="$(readlink -f "${ROOT_DIR}/docs/Solidity.g4")" + +SGR_RESET="\033[0m" +SGR_BOLD="\033[1m" +SGR_GREEN="\033[32m" +SGR_RED="\033[31m" +SGR_BLUE="\033[34m" + +vt_cursor_up() { echo -ne "\033[A"; } +vt_cursor_begin_of_line() { echo -ne "\r"; } + +download_antlr4() +{ + if [[ ! -e "$ANTLR_JAR" ]] + then + curl -o "${ANTLR_JAR}" "${ANTLR_JAR_URI}" + fi +} + +prepare_workdir() +{ + mkdir -p "${ROOT_DIR}/build/deps" + mkdir -p "${WORKDIR}" + mkdir -p "${WORKDIR}/src" + mkdir -p "${WORKDIR}/target" +} + +prepare_workdir +download_antlr4 + +if [[ ! -f "${WORKDIR}/target/SolidityParser.class" ]] || \ + [ "${GRAMMAR_FILE}" -nt "${WORKDIR}/target/SolidityParser.class" ] +then + echo "Creating parser" + # Create lexer/parser from grammar + java -jar "${ANTLR_JAR}" "${GRAMMAR_FILE}" -o "${WORKDIR}/src/" + + # Compile lexer/parser sources + javac -classpath "${ANTLR_JAR}" "${WORKDIR}/src/"*.java -d "${WORKDIR}/target/" +fi + +# Run tests +failed_count=0 +test_file() +{ + local SOL_FILE + SOL_FILE="$(readlink -m "${1}")" + local cur=${2} + local max=${3} + + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ..." + local output + output=$( + java \ + -classpath "${ANTLR_JAR}:${WORKDIR}/target/" \ + "org.antlr.v4.gui.TestRig" \ + Solidity \ + sourceUnit <"${SOL_FILE}" 2>&1 + ) + vt_cursor_up + vt_cursor_begin_of_line + if [[ "${output}" == "" ]] + then + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ${SGR_BOLD}${SGR_GREEN}OK${SGR_RESET}" + else + echo -e "${SGR_BLUE}[${cur}/${max}] Testing ${SOL_FILE}${SGR_RESET} ${SGR_BOLD}${SGR_RED}FAILED${SGR_RESET}" + echo "${output}" + failed_count=$((failed_count + 1)) + exit 1 + fi +} + +# we only want to use files that do not contain errors or multi-source files. +SOL_FILES=() +while IFS='' read -r line +do + SOL_FILES+=("$line") +done < <( + grep -riL -E \ + "^\/\/ (Syntax|Type|Parser|Declaration)Error|^==== Source:" \ + "${ROOT_DIR}/test/libsolidity/syntaxTests" \ + "${ROOT_DIR}/test/libsolidity/semanticTests" \ +) + +test_count=0 +for SOL_FILE in "${SOL_FILES[@]}" +do + test_count=$((test_count + 1)) + test_file "${SOL_FILE}" ${test_count} ${#SOL_FILES[*]} +done + +echo "Summary: ${failed_count} of ${#SOL_FILES[*]} sources failed." +exit ${failed_count} From 42b143098e4fdea625da062575f400261b806558 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 24 Mar 2020 13:04:07 +0100 Subject: [PATCH 100/165] Add natspec test with too many return tags --- .../natspec/docstring_too_many_return_tags.sol | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/libsolidity/syntaxTests/natspec/docstring_too_many_return_tags.sol diff --git a/test/libsolidity/syntaxTests/natspec/docstring_too_many_return_tags.sol b/test/libsolidity/syntaxTests/natspec/docstring_too_many_return_tags.sol new file mode 100644 index 000000000000..7197a4edb719 --- /dev/null +++ b/test/libsolidity/syntaxTests/natspec/docstring_too_many_return_tags.sol @@ -0,0 +1,8 @@ +abstract contract C { + /// @param id Some identifier + /// @return value Some value + /// @return value2 Some value 2 + function vote(uint id) public virtual returns (uint value); +} +// ---- +// DocstringParsingError: (26-121): Documentation tag "@return value2 Some value 2" exceeds the number of return parameters. From 04d8ad2ae1425667d4340cf93b047f40dfbd8294 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 10 Mar 2020 14:30:04 +0100 Subject: [PATCH 101/165] Legacy codegeneration for immutable state variables. --- libevmasm/Assembly.cpp | 89 +++++++++++++++- libevmasm/Assembly.h | 5 + libevmasm/AssemblyItem.cpp | 23 ++++ libevmasm/AssemblyItem.h | 8 +- libevmasm/KnownState.cpp | 4 + libevmasm/LinkerObject.h | 4 + libevmasm/SemanticInformation.cpp | 2 + libsolidity/ast/Types.cpp | 10 ++ libsolidity/ast/Types.h | 2 + libsolidity/codegen/CompilerContext.cpp | 56 ++++++++++ libsolidity/codegen/CompilerContext.h | 23 +++- libsolidity/codegen/CompilerUtils.cpp | 4 +- libsolidity/codegen/ContractCompiler.cpp | 27 ++++- libsolidity/codegen/ContractCompiler.h | 1 + libsolidity/codegen/ExpressionCompiler.cpp | 2 +- libsolidity/codegen/LValue.cpp | 36 +++++++ libsolidity/codegen/LValue.h | 45 ++++++-- libyul/AssemblyStack.cpp | 1 + test/libevmasm/Optimiser.cpp | 100 ++++++++++++++++++ .../immutable/external_function_pointer.sol | 20 ++++ .../immutable/read_during_creation.sol | 13 +++ .../semanticTests/immutable/stub.sol | 13 +++ 22 files changed, 471 insertions(+), 17 deletions(-) create mode 100644 test/libsolidity/semanticTests/immutable/external_function_pointer.sol create mode 100644 test/libsolidity/semanticTests/immutable/read_during_creation.sol create mode 100644 test/libsolidity/semanticTests/immutable/stub.sol diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 7ed44d236ab0..e67ccb8f502e 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -283,6 +283,24 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) createJsonValue("PUSHDEPLOYADDRESS", sourceIndex, i.location().start, i.location().end) ); break; + case PushImmutable: + collection.append(createJsonValue( + "PUSHIMMUTABLE", + sourceIndex, + i.location().start, + i.location().end, + m_immutables.at(h256(i.data())) + )); + break; + case AssignImmutable: + collection.append(createJsonValue( + "ASSIGNIMMUTABLE", + sourceIndex, + i.location().start, + i.location().end, + m_immutables.at(h256(i.data())) + )); + break; case Tag: collection.append( createJsonValue("tag", sourceIndex, i.location().start, i.location().end, toString(i.data()))); @@ -333,6 +351,20 @@ AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier) return AssemblyItem{PushLibraryAddress, h}; } +AssemblyItem Assembly::newPushImmutable(string const& _identifier) +{ + h256 h(util::keccak256(_identifier)); + m_immutables[h] = _identifier; + return AssemblyItem{PushImmutable, h}; +} + +AssemblyItem Assembly::newImmutableAssignment(string const& _identifier) +{ + h256 h(util::keccak256(_identifier)); + m_immutables[h] = _identifier; + return AssemblyItem{AssignImmutable, h}; +} + Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs) { OptimiserSettings settings; @@ -495,16 +527,44 @@ LinkerObject const& Assembly::assemble() const // Otherwise ensure the object is actually clear. assertThrow(m_assembledObject.linkReferences.empty(), AssemblyException, "Unexpected link references."); + LinkerObject& ret = m_assembledObject; + size_t subTagSize = 1; + map> immutableReferencesBySub; for (auto const& sub: m_subs) { - sub->assemble(); + auto const& linkerObject = sub->assemble(); + if (!linkerObject.immutableReferences.empty()) + { + assertThrow( + immutableReferencesBySub.empty(), + AssemblyException, + "More than one sub-assembly references immutables." + ); + immutableReferencesBySub = linkerObject.immutableReferences; + } for (size_t tagPos: sub->m_tagPositionsInBytecode) if (tagPos != size_t(-1) && tagPos > subTagSize) subTagSize = tagPos; } - LinkerObject& ret = m_assembledObject; + bool setsImmutables = false; + bool pushesImmutables = false; + + for (auto const& i: m_items) + if (i.type() == AssignImmutable) + { + i.setImmutableOccurrences(immutableReferencesBySub[i.data()].size()); + setsImmutables = true; + } + else if (i.type() == PushImmutable) + pushesImmutables = true; + if (setsImmutables || pushesImmutables) + assertThrow( + setsImmutables != pushesImmutables, + AssemblyException, + "Cannot push and assign immutables in the same assembly subroutine." + ); size_t bytesRequiredForCode = bytesRequired(subTagSize); m_tagPositionsInBytecode = vector(m_usedTags, -1); @@ -598,6 +658,24 @@ LinkerObject const& Assembly::assemble() const ret.linkReferences[ret.bytecode.size()] = m_libraries.at(i.data()); ret.bytecode.resize(ret.bytecode.size() + 20); break; + case PushImmutable: + ret.bytecode.push_back(uint8_t(Instruction::PUSH32)); + ret.immutableReferences[i.data()].emplace_back(ret.bytecode.size()); + ret.bytecode.resize(ret.bytecode.size() + 32); + break; + case AssignImmutable: + for (auto const& offset: immutableReferencesBySub[i.data()]) + { + ret.bytecode.push_back(uint8_t(Instruction::DUP1)); + // TODO: should we make use of the constant optimizer methods for pushing the offsets? + bytes offsetBytes = toCompactBigEndian(u256(offset)); + ret.bytecode.push_back(uint8_t(Instruction::PUSH1) - 1 + offsetBytes.size()); + ret.bytecode += offsetBytes; + ret.bytecode.push_back(uint8_t(Instruction::MSTORE)); + } + immutableReferencesBySub.erase(i.data()); + ret.bytecode.push_back(uint8_t(Instruction::POP)); + break; case PushDeployTimeAddress: ret.bytecode.push_back(uint8_t(Instruction::PUSH20)); ret.bytecode.resize(ret.bytecode.size() + 20); @@ -615,6 +693,13 @@ LinkerObject const& Assembly::assemble() const } } + assertThrow( + immutableReferencesBySub.empty(), + AssemblyException, + "Some immutables were read from but never assigned." + ); + + if (!m_subs.empty() || !m_data.empty() || !m_auxiliaryData.empty()) // Append an INVALID here to help tests find miscompilation. ret.bytecode.push_back(uint8_t(Instruction::INVALID)); diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index a76538375c9b..e9e3630a8af0 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -54,6 +54,8 @@ class Assembly Assembly& sub(size_t _sub) { return *m_subs.at(_sub); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); + AssemblyItem newPushImmutable(std::string const& _identifier); + AssemblyItem newImmutableAssignment(std::string const& _identifier); AssemblyItem const& append(AssemblyItem const& _i); AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } @@ -64,6 +66,8 @@ class Assembly /// after compilation and CODESIZE is not an option. void appendProgramSize() { append(AssemblyItem(PushProgramSize)); } void appendLibraryAddress(std::string const& _identifier) { append(newPushLibraryAddress(_identifier)); } + void appendImmutable(std::string const& _identifier) { append(newPushImmutable(_identifier)); } + void appendImmutableAssignment(std::string const& _identifier) { append(newImmutableAssignment(_identifier)); } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } @@ -166,6 +170,7 @@ class Assembly std::vector> m_subs; std::map m_strings; std::map m_libraries; ///< Identifiers of libraries to be linked. + std::map m_immutables; ///< Identifiers of immutables. mutable LinkerObject m_assembledObject; mutable std::vector m_tagPositionsInBytecode; diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index c238a3a3c741..610c6f5dd246 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -80,6 +80,13 @@ unsigned AssemblyItem::bytesRequired(unsigned _addressLength) const case PushLibraryAddress: case PushDeployTimeAddress: return 1 + 20; + case PushImmutable: + return 1 + 32; + case AssignImmutable: + if (m_immutableOccurrences) + return 1 + (3 + 32) * *m_immutableOccurrences; + else + return 1 + (3 + 32) * 1024; // 1024 occurrences are beyond the maximum code size anyways. default: break; } @@ -90,6 +97,8 @@ int AssemblyItem::arguments() const { if (type() == Operation) return instructionInfo(instruction()).args; + else if (type() == AssignImmutable) + return 1; else return 0; } @@ -108,6 +117,7 @@ int AssemblyItem::returnValues() const case PushSubSize: case PushProgramSize: case PushLibraryAddress: + case PushImmutable: case PushDeployTimeAddress: return 1; case Tag: @@ -135,6 +145,7 @@ bool AssemblyItem::canBeFunctional() const case PushProgramSize: case PushLibraryAddress: case PushDeployTimeAddress: + case PushImmutable: return true; case Tag: return false; @@ -210,6 +221,12 @@ string AssemblyItem::toAssemblyText() const case PushDeployTimeAddress: text = string("deployTimeAddress()"); break; + case PushImmutable: + text = string("immutable(\"") + toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add) + "\")"; + break; + case AssignImmutable: + text = string("assignImmutable(\"") + toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add) + "\")"; + break; case UndefinedItem: assertThrow(false, AssemblyException, "Invalid assembly item."); break; @@ -275,6 +292,12 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item) case PushDeployTimeAddress: _out << " PushDeployTimeAddress"; break; + case PushImmutable: + _out << " PushImmutable"; + break; + case AssignImmutable: + _out << " AssignImmutable"; + break; case UndefinedItem: _out << " ???"; break; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index e506a9fdb3e0..fc8c63c6718b 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -44,7 +44,9 @@ enum AssemblyItemType { Tag, PushData, PushLibraryAddress, ///< Push a currently unknown address of another (library) contract. - PushDeployTimeAddress ///< Push an address to be filled at deploy time. Should not be touched by the optimizer. + PushDeployTimeAddress, ///< Push an address to be filled at deploy time. Should not be touched by the optimizer. + PushImmutable, ///< Push the currently unknown value of an immutable variable. The actual value will be filled in by the constructor. + AssignImmutable ///< Assigns the current value on the stack to an immutable variable. Only valid during creation code. }; class Assembly; @@ -153,6 +155,8 @@ class AssemblyItem size_t m_modifierDepth = 0; + void setImmutableOccurrences(size_t _n) const { m_immutableOccurrences = std::make_shared(_n); } + private: AssemblyItemType m_type; Instruction m_instruction; ///< Only valid if m_type == Operation @@ -162,6 +166,8 @@ class AssemblyItem /// Pushed value for operations with data to be determined during assembly stage, /// e.g. PushSubSize, PushTag, PushSub, etc. mutable std::shared_ptr m_pushedValue; + /// Number of PushImmutable's with the same hash. Only used for AssignImmutable. + mutable std::shared_ptr m_immutableOccurrences; }; inline size_t bytesRequired(AssemblyItems const& _items, size_t _addressLength) diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 7e447a9a1fd6..5f1ca736cb23 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -91,6 +91,10 @@ KnownState::StoreOperation KnownState::feedItem(AssemblyItem const& _item, bool { // can be ignored } + else if (_item.type() == AssignImmutable) + // Since AssignImmutable breaks blocks, it should be fine to only consider its changes to the stack, which + // is the same as POP. + return feedItem(AssemblyItem(Instruction::POP), _copyItem); else if (_item.type() != Operation) { assertThrow(_item.deposit() == 1, InvalidDeposit, ""); diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index e7a1e9667b7d..ccf5588bb334 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -40,6 +40,10 @@ struct LinkerObject /// need to be replaced by the actual addresses by the linker. std::map linkReferences; + /// Map from hashes of the identifiers of immutable variables to a list of offsets into the bytecode + /// that refer to their values. + std::map> immutableReferences; + /// Appends the bytecode of @a _other and incorporates its link references. void append(LinkerObject const& _other); diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 4ea9a01aee37..76eeb59566f3 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -36,6 +36,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool case UndefinedItem: case Tag: case PushDeployTimeAddress: + case AssignImmutable: return true; case Push: case PushString: @@ -45,6 +46,7 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool case PushProgramSize: case PushData: case PushLibraryAddress: + case PushImmutable: return false; case Operation: { diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 9ed35e694fce..76eeb4fceec6 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2012,6 +2012,16 @@ vector> ContractType::stateVar return variablesAndOffsets; } +vector ContractType::immutableVariables() const +{ + vector variables; + for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts)) + for (VariableDeclaration const* variable: contract->stateVariables()) + if (variable->immutable()) + variables.push_back(variable); + return variables; +} + vector> ContractType::makeStackItems() const { if (m_super) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 73943b18ade6..d0e774cb7cc7 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -895,6 +895,8 @@ class ContractType: public Type /// @returns a list of all state variables (including inherited) of the contract and their /// offsets in storage. std::vector> stateVariables() const; + /// @returns a list of all immutable variables (including inherited) of the contract. + std::vector immutableVariables() const; protected: std::vector> makeStackItems() const override; private: diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index cb195c49fa73..26cff59eccba 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -71,6 +71,55 @@ void CompilerContext::addStateVariable( m_stateVariables[&_declaration] = make_pair(_storageOffset, _byteOffset); } +void CompilerContext::addImmutable(VariableDeclaration const& _variable) +{ + solAssert(_variable.immutable(), "Attempted to register a non-immutable variable as immutable."); + solUnimplementedAssert(_variable.annotation().type->isValueType(), "Only immutable variables of value type are supported."); + solAssert(m_runtimeContext, "Attempted to register an immutable variable for runtime code generation."); + m_immutableVariables[&_variable] = CompilerUtils::generalPurposeMemoryStart + *m_reservedMemory; + solAssert(_variable.annotation().type->memoryHeadSize() == 32, "Memory writes might overlap."); + *m_reservedMemory += _variable.annotation().type->memoryHeadSize(); +} + +size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variable) const +{ + solAssert(m_immutableVariables.count(&_variable), "Memory offset of unknown immutable queried."); + solAssert(m_runtimeContext, "Attempted to fetch the memory offset of an immutable variable during runtime code generation."); + return m_immutableVariables.at(&_variable); +} + +vector CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable) +{ + string baseName = + _variable.annotation().contract->fullyQualifiedName() + + "." + + _variable.name() + + " (" + + to_string(_variable.id()) + + ")"; + solAssert(_variable.annotation().type->sizeOnStack() > 0, ""); + if (_variable.annotation().type->sizeOnStack() == 1) + return {baseName}; + vector names; + auto collectSlotNames = [&](string const& _baseName, TypePointer type, auto const& _recurse) -> void { + for (auto const& [slot, type]: type->stackItems()) + if (type) + _recurse(_baseName + " " + slot, type, _recurse); + else + names.emplace_back(_baseName); + }; + collectSlotNames(baseName, _variable.annotation().type, collectSlotNames); + return names; +} + +size_t CompilerContext::reservedMemory() +{ + solAssert(m_reservedMemory.has_value(), "Reserved memory was used before "); + size_t reservedMemory = *m_reservedMemory; + m_reservedMemory = std::nullopt; + return reservedMemory; +} + void CompilerContext::startFunction(Declaration const& _function) { m_functionCompilationQueue.startFunction(_function); @@ -500,6 +549,13 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _ #endif } +LinkerObject const& CompilerContext::assembledObject() const +{ + LinkerObject const& object = m_asm->assemble(); + solAssert(object.immutableReferences.empty(), "Leftover immutables."); + return object; +} + FunctionDefinition const& CompilerContext::resolveVirtualFunction( FunctionDefinition const& _function, vector::const_iterator _searchStart diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 8c577523916f..ec846af83101 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -64,6 +64,7 @@ class CompilerContext m_asm(std::make_shared()), m_evmVersion(_evmVersion), m_revertStrings(_revertStrings), + m_reservedMemory{0}, m_runtimeContext(_runtimeContext), m_abiFunctions(m_evmVersion, m_revertStrings, m_yulFunctionCollector), m_yulUtilFunctions(m_evmVersion, m_revertStrings, m_yulFunctionCollector) @@ -80,6 +81,16 @@ class CompilerContext bool experimentalFeatureActive(ExperimentalFeature _feature) const { return m_experimentalFeatures.count(_feature); } void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); + void addImmutable(VariableDeclaration const& _declaration); + + /// @returns the reserved memory for storing the value of the immutable @a _variable during contract creation. + size_t immutableMemoryOffset(VariableDeclaration const& _variable) const; + /// @returns a list of slot names referring to the stack slots of an immutable variable. + static std::vector immutableVariableSlotNames(VariableDeclaration const& _variable); + + /// @returns the reserved memory and resets it to mark it as used. + size_t reservedMemory(); + void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void removeVariable(Declaration const& _declaration); /// Removes all local variables currently allocated above _stackHeight. @@ -217,6 +228,10 @@ class CompilerContext evmasm::AssemblyItem appendData(bytes const& _data) { return m_asm->append(_data); } /// Appends the address (virtual, will be filled in by linker) of a library. void appendLibraryAddress(std::string const& _identifier) { m_asm->appendLibraryAddress(_identifier); } + /// Appends an immutable variable. The value will be filled in by the constructor. + void appendImmutable(std::string const& _identifier) { m_asm->appendImmutable(_identifier); } + /// Appends an assignment to an immutable variable. Only valid in creation code. + void appendImmutableAssignment(std::string const& _identifier) { m_asm->appendImmutableAssignment(_identifier); } /// Appends a zero-address that can be replaced by something else at deploy time (if the /// position in bytecode is known). void appendDeployTimeAddress() { m_asm->append(evmasm::PushDeployTimeAddress); } @@ -282,7 +297,7 @@ class CompilerContext return m_asm->assemblyJSON(_indicies); } - evmasm::LinkerObject const& assembledObject() const { return m_asm->assemble(); } + evmasm::LinkerObject const& assembledObject() const; evmasm::LinkerObject const& assembledRuntimeObject(size_t _subIndex) const { return m_asm->sub(_subIndex).assemble(); } /** @@ -355,6 +370,12 @@ class CompilerContext std::map> m_otherCompilers; /// Storage offsets of state variables std::map> m_stateVariables; + /// Memory offsets reserved for the values of immutable variables during contract creation. + std::map m_immutableVariables; + /// Total amount of reserved memory. Reserved memory is used to store immutable variables during contract creation. + /// This has to be finalized before initialiseFreeMemoryPointer() is called. That function + /// will reset the optional to verify that. + std::optional m_reservedMemory = {0}; /// Offsets of local variables on the stack (relative to stack base). /// This needs to be a stack because if a modifier contains a local variable and this /// modifier is applied twice, the position of the variable needs to be restored diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index c559c0b7c8a5..d4f35ad793e3 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -51,7 +51,9 @@ static_assert(CompilerUtils::generalPurposeMemoryStart >= CompilerUtils::zeroPoi void CompilerUtils::initialiseFreeMemoryPointer() { - m_context << u256(generalPurposeMemoryStart); + size_t reservedMemory = m_context.reservedMemory(); + solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63, ""); + m_context << (u256(generalPurposeMemoryStart) + reservedMemory); storeFreeMemoryPointer(); } diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6fffbd5b50ab..d5f5ffe3308f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -130,6 +130,8 @@ void ContractCompiler::initializeContext( m_context.setExperimentalFeatures(_contract.sourceUnit().annotation().experimentalFeatures); m_context.setOtherCompilers(_otherCompilers); m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts); + if (m_runtimeCompiler) + registerImmutableVariables(_contract); CompilerUtils(m_context).initialiseFreeMemoryPointer(); registerStateVariables(_contract); m_context.resetVisitedNodes(&_contract); @@ -183,10 +185,26 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont m_context << deployRoutine; solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + + ContractType contractType(_contract); + auto const& immutables = contractType.immutableVariables(); + // Push all immutable values on the stack. + for (auto const& immutable: immutables) + CompilerUtils(m_context).loadFromMemory(m_context.immutableMemoryOffset(*immutable), *immutable->annotation().type); m_context.pushSubroutineSize(m_context.runtimeSub()); - m_context << Instruction::DUP1; + if (immutables.empty()) + m_context << Instruction::DUP1; m_context.pushSubroutineOffset(m_context.runtimeSub()); m_context << u256(0) << Instruction::CODECOPY; + // Assign immutable values from stack in reversed order. + for (auto const& immutable: immutables | boost::adaptors::reversed) + { + auto slotNames = m_context.immutableVariableSlotNames(*immutable); + for (auto&& slotName: slotNames | boost::adaptors::reversed) + m_context.appendImmutableAssignment(slotName); + } + if (!immutables.empty()) + m_context.pushSubroutineSize(m_context.runtimeSub()); m_context << u256(0) << Instruction::RETURN; return m_context.runtimeSub(); @@ -521,6 +539,13 @@ void ContractCompiler::registerStateVariables(ContractDefinition const& _contrac m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var)); } +void ContractCompiler::registerImmutableVariables(ContractDefinition const& _contract) +{ + solAssert(m_runtimeCompiler, "Attempted to register immutables for runtime code generation."); + for (auto const& var: ContractType(_contract).immutableVariables()) + m_context.addImmutable(*var); +} + void ContractCompiler::initializeStateVariables(ContractDefinition const& _contract) { solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library."); diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 0a2ecf7e8741..0916da281a2b 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -99,6 +99,7 @@ class ContractCompiler: private ASTConstVisitor void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary); void registerStateVariables(ContractDefinition const& _contract); + void registerImmutableVariables(ContractDefinition const& _contract); void initializeStateVariables(ContractDefinition const& _contract); bool visit(VariableDeclaration const& _variableDeclaration) override; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index d4f3d460da08..c71d067c4ae8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2436,7 +2436,7 @@ void ExpressionCompiler::appendVariable(VariableDeclaration const& _variable, Ex if (_variable.isConstant()) acceptAndConvert(*_variable.value(), *_variable.annotation().type); else if (_variable.immutable()) - solUnimplemented(""); + setLValue(_expression, _variable); else setLValueFromDeclaration(_variable, _expression); } diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 5fd17bf5c1b7..4b1c80ede88d 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -144,6 +144,42 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const m_context << Instruction::POP; } + +ImmutableItem::ImmutableItem(CompilerContext& _compilerContext, VariableDeclaration const& _variable): + LValue(_compilerContext, _variable.annotation().type), m_variable(_variable) +{ + solAssert(_variable.immutable(), ""); +} + +void ImmutableItem::retrieveValue(SourceLocation const&, bool) const +{ + solUnimplementedAssert(m_dataType->isValueType(), ""); + solAssert(!m_context.runtimeContext(), "Tried to read immutable at construction time."); + for (auto&& slotName: m_context.immutableVariableSlotNames(m_variable)) + m_context.appendImmutable(slotName); +} + +void ImmutableItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const +{ + CompilerUtils utils(m_context); + solUnimplementedAssert(m_dataType->isValueType(), ""); + solAssert(_sourceType.isValueType(), ""); + + utils.convertType(_sourceType, *m_dataType, true); + m_context << m_context.immutableMemoryOffset(m_variable); + if (_move) + utils.moveIntoStack(m_dataType->sizeOnStack()); + else + utils.copyToStackTop(m_dataType->sizeOnStack() + 1, m_dataType->sizeOnStack()); + utils.storeInMemoryDynamic(*m_dataType, false); + m_context << Instruction::POP; +} + +void ImmutableItem::setToZero(SourceLocation const&, bool) const +{ + solAssert(false, "Attempted to set immutable variable to zero."); +} + StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): StorageItem(_compilerContext, *_declaration.annotation().type) { diff --git a/libsolidity/codegen/LValue.h b/libsolidity/codegen/LValue.h index 1cd4def01b50..cd72f37e00a3 100644 --- a/libsolidity/codegen/LValue.h +++ b/libsolidity/codegen/LValue.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include #include @@ -82,12 +83,12 @@ class StackVariable: public LValue unsigned sizeOnStack() const override { return 0; } void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; - virtual void storeValue( + void storeValue( Type const& _sourceType, langutil::SourceLocation const& _location = {}, bool _move = false ) const override; - virtual void setToZero( + void setToZero( langutil::SourceLocation const& _location = {}, bool _removeReference = true ) const override; @@ -108,12 +109,12 @@ class MemoryItem: public LValue MemoryItem(CompilerContext& _compilerContext, Type const& _type, bool _padded = true); unsigned sizeOnStack() const override { return 1; } void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; - virtual void storeValue( + void storeValue( Type const& _sourceType, langutil::SourceLocation const& _location = {}, bool _move = false ) const override; - virtual void setToZero( + void setToZero( langutil::SourceLocation const& _location = {}, bool _removeReference = true ) const override; @@ -122,6 +123,30 @@ class MemoryItem: public LValue bool m_padded = false; }; +/** + * Reference to an immutable variable. During contract creation this refers to a location in memory. At the + * end of contract creation the values from these memory locations are copied into all occurrences of the immutable + * variable in the runtime code. + */ +class ImmutableItem: public LValue +{ +public: + ImmutableItem(CompilerContext& _compilerContext, VariableDeclaration const& _variable); + unsigned sizeOnStack() const override { return 0; } + void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; + void storeValue( + Type const& _sourceType, + langutil::SourceLocation const& _location = {}, + bool _move = false + ) const override; + void setToZero( + langutil::SourceLocation const& _location = {}, + bool _removeReference = true + ) const override; +private: + VariableDeclaration const& m_variable; +}; + /** * Reference to some item in storage. On the stack this is , * where 0 <= offset_inside_value < 32 and an offset of i means that the value is multiplied @@ -136,12 +161,12 @@ class StorageItem: public LValue StorageItem(CompilerContext& _compilerContext, Type const& _type); unsigned sizeOnStack() const override { return 2; } void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; - virtual void storeValue( + void storeValue( Type const& _sourceType, langutil::SourceLocation const& _location = {}, bool _move = false ) const override; - virtual void setToZero( + void setToZero( langutil::SourceLocation const& _location = {}, bool _removeReference = true ) const override; @@ -158,12 +183,12 @@ class StorageByteArrayElement: public LValue StorageByteArrayElement(CompilerContext& _compilerContext); unsigned sizeOnStack() const override { return 2; } void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; - virtual void storeValue( + void storeValue( Type const& _sourceType, langutil::SourceLocation const& _location = {}, bool _move = false ) const override; - virtual void setToZero( + void setToZero( langutil::SourceLocation const& _location = {}, bool _removeReference = true ) const override; @@ -180,12 +205,12 @@ class TupleObject: public LValue TupleObject(CompilerContext& _compilerContext, std::vector>&& _lvalues); unsigned sizeOnStack() const override; void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override; - virtual void storeValue( + void storeValue( Type const& _sourceType, langutil::SourceLocation const& _location = {}, bool _move = false ) const override; - virtual void setToZero( + void setToZero( langutil::SourceLocation const& _location = {}, bool _removeReference = true ) const override; diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 7c0eca27621c..e64420bd91fd 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -203,6 +203,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const EthAssemblyAdapter adapter(assembly); compileEVM(adapter, false, m_optimiserSettings.optimizeStackAllocation); object.bytecode = make_shared(assembly.assemble()); + yulAssert(object.bytecode->immutableReferences.empty(), "Leftover immutables."); object.assembly = assembly.assemblyString(); object.sourceMappings = make_unique( evmasm::AssemblyItem::computeSourceMapping( diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp index 4d93f4e76914..782b687fc0d3 100644 --- a/test/libevmasm/Optimiser.cpp +++ b/test/libevmasm/Optimiser.cpp @@ -112,6 +112,44 @@ namespace BOOST_AUTO_TEST_SUITE(Optimiser) +BOOST_AUTO_TEST_CASE(cse_push_immutable_same) +{ + AssemblyItem pushImmutable{PushImmutable, 0x1234}; + checkCSE({pushImmutable, pushImmutable}, {pushImmutable, Instruction::DUP1}); +} + +BOOST_AUTO_TEST_CASE(cse_push_immutable_different) +{ + AssemblyItems input{{PushImmutable, 0x1234},{PushImmutable, 0xABCD}}; + checkCSE(input, input); +} + +BOOST_AUTO_TEST_CASE(cse_assign_immutable) +{ + { + AssemblyItems input{u256(0x42), {AssignImmutable, 0x1234}}; + checkCSE(input, input); + } + { + AssemblyItems input{{AssignImmutable, 0x1234}}; + checkCSE(input, input); + } +} + + +BOOST_AUTO_TEST_CASE(cse_assign_immutable_breaks) +{ + AssemblyItems input = addDummyLocations(AssemblyItems{ + u256(0x42), + {AssignImmutable, 0x1234}, + Instruction::ORIGIN + }); + + evmasm::CommonSubexpressionEliminator cse{evmasm::KnownState()}; + // Make sure CSE breaks after AssignImmutable. + BOOST_REQUIRE(cse.feedItems(input.begin(), input.end(), false) == input.begin() + 2); +} + BOOST_AUTO_TEST_CASE(cse_intermediate_swap) { evmasm::KnownState state; @@ -798,6 +836,68 @@ BOOST_AUTO_TEST_CASE(block_deduplicator) BOOST_CHECK_EQUAL(pushTags.size(), 2); } +BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_same) +{ + AssemblyItems blocks{ + AssemblyItem(Tag, 1), + u256(42), + AssemblyItem{AssignImmutable, 0x1234}, + Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(42), + AssemblyItem{AssignImmutable, 0x1234}, + Instruction::JUMP + }; + + AssemblyItems input = AssemblyItems{ + AssemblyItem(PushTag, 2), + AssemblyItem(PushTag, 1), + } + blocks; + AssemblyItems output = AssemblyItems{ + AssemblyItem(PushTag, 1), + AssemblyItem(PushTag, 1), + } + blocks; + BlockDeduplicator dedup(input); + dedup.deduplicate(); + BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_value) +{ + AssemblyItems input{ + AssemblyItem(PushTag, 2), + AssemblyItem(PushTag, 1), + AssemblyItem(Tag, 1), + u256(42), + AssemblyItem{AssignImmutable, 0x1234}, + Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(23), + AssemblyItem{AssignImmutable, 0x1234}, + Instruction::JUMP + }; + BlockDeduplicator dedup(input); + BOOST_CHECK(!dedup.deduplicate()); +} + +BOOST_AUTO_TEST_CASE(block_deduplicator_assign_immutable_different_hash) +{ + AssemblyItems input{ + AssemblyItem(PushTag, 2), + AssemblyItem(PushTag, 1), + AssemblyItem(Tag, 1), + u256(42), + AssemblyItem{AssignImmutable, 0x1234}, + Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(42), + AssemblyItem{AssignImmutable, 0xABCD}, + Instruction::JUMP + }; + BlockDeduplicator dedup(input); + BOOST_CHECK(!dedup.deduplicate()); +} + BOOST_AUTO_TEST_CASE(block_deduplicator_loops) { AssemblyItems input{ diff --git a/test/libsolidity/semanticTests/immutable/external_function_pointer.sol b/test/libsolidity/semanticTests/immutable/external_function_pointer.sol new file mode 100644 index 000000000000..f671065ace8e --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/external_function_pointer.sol @@ -0,0 +1,20 @@ +contract D { + function f() external view returns (uint256) { + return 42; + } +} +contract C { + D d; + function() external view returns(uint256) immutable z; + constructor() public { + d = new D(); + z = d.f; + } + function f() public view returns (uint256) { + assert(z.address == address(d)); + assert(z.selector == D.f.selector); + return z(); + } +} +// ---- +// f() -> 42 diff --git a/test/libsolidity/semanticTests/immutable/read_during_creation.sol b/test/libsolidity/semanticTests/immutable/read_during_creation.sol new file mode 100644 index 000000000000..4a037cadceae --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/read_during_creation.sol @@ -0,0 +1,13 @@ +contract C { + uint256 immutable x; + uint256 immutable y; + constructor() public { + x = 42; + y = x; + } + function f() public view returns (uint256, uint256) { + return (x+x,y); + } +} +// ---- +// f() -> 84, 42 diff --git a/test/libsolidity/semanticTests/immutable/stub.sol b/test/libsolidity/semanticTests/immutable/stub.sol new file mode 100644 index 000000000000..ee9ed0678c44 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/stub.sol @@ -0,0 +1,13 @@ +contract C { + uint256 immutable x; + uint256 immutable y; + constructor() public { + x = 42; + y = 23; + } + function f() public view returns (uint256, uint256) { + return (x+x,y); + } +} +// ---- +// f() -> 84, 23 From e255c15227a295dba2657b3c4c2a8f51c48a66ab Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 12 Mar 2020 17:32:10 +0100 Subject: [PATCH 102/165] Tests. --- test/libevmasm/Assembler.cpp | 117 +++++++++++++++++- .../immutable/external_function_pointer.sol | 24 ++-- .../semanticTests/immutable/inheritance.sol | 30 +++++ .../immutable/internal_function_pointer.sol | 15 +++ .../immutable/multi_creation.sol | 31 +++++ .../immutable/read_during_creation.sol | 13 -- .../semanticTests/immutable/stub.sol | 18 +-- .../semanticTests/immutable/use_scratch.sol | 19 +++ 8 files changed, 229 insertions(+), 38 deletions(-) create mode 100644 test/libsolidity/semanticTests/immutable/inheritance.sol create mode 100644 test/libsolidity/semanticTests/immutable/internal_function_pointer.sol create mode 100644 test/libsolidity/semanticTests/immutable/multi_creation.sol delete mode 100644 test/libsolidity/semanticTests/immutable/read_during_creation.sol create mode 100644 test/libsolidity/semanticTests/immutable/use_scratch.sol diff --git a/test/libevmasm/Assembler.cpp b/test/libevmasm/Assembler.cpp index 2d7057f7c050..a402101c4ee2 100644 --- a/test/libevmasm/Assembler.cpp +++ b/test/libevmasm/Assembler.cpp @@ -61,6 +61,8 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) Assembly _subAsm; auto sub_asm = make_shared("lorem ipsum", "sub.asm"); _subAsm.setSourceLocation({6, 8, sub_asm}); + // PushImmutable + _subAsm.appendImmutable("someImmutable"); _subAsm.append(Instruction::INVALID); shared_ptr _subAsmPtr = make_shared(_subAsm); @@ -86,6 +88,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) _assembly.pushSubroutineOffset(size_t(sub.data())); // PushDeployTimeAddress _assembly.append(PushDeployTimeAddress); + // AssignImmutable. + // Note that since there is no reference to "someOtherImmutable", this will compile to a simple POP in the hex output. + _assembly.appendImmutableAssignment("someOtherImmutable"); + _assembly.append(u256(2)); + _assembly.appendImmutableAssignment("someImmutable"); // Operation _assembly.append(Instruction::STOP); _assembly.appendAuxiliaryDataToEnd(bytes{0x42, 0x66}); @@ -95,8 +102,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) BOOST_CHECK_EQUAL( _assembly.assemble().toHex(), - "5b6001600220604673__$bf005014d9d0f534b8fcb268bd84c491a2$__" - "600056603e6001603d73000000000000000000000000000000000000000000fe" + "5b6001600220606f73__$bf005014d9d0f534b8fcb268bd84c491a2$__" + "60005660676022604573000000000000000000000000000000000000000050" + "60028060015250" + "00fe" + "7f0000000000000000000000000000000000000000000000000000000000000000" "fe010203044266eeaa" ); BOOST_CHECK_EQUAL( @@ -111,12 +121,16 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) " dataSize(sub_0)\n" " dataOffset(sub_0)\n" " deployTimeAddress()\n" + " assignImmutable(\"0xc3978657661c4d8e32e3d5f42597c009f0d3859e9f9d0d94325268f9799e2bfb\")\n" + " 0x02\n" + " assignImmutable(\"0x26f2c0195e9d408feff3abd77d83f2971f3c9a18d1e8a9437c7835ae4211fc9f\")\n" " stop\n" "stop\n" "data_a6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b 01020304\n" "\n" "sub_0: assembly {\n" " /* \"sub.asm\":6:8 */\n" + " immutable(\"0x26f2c0195e9d408feff3abd77d83f2971f3c9a18d1e8a9437c7835ae4211fc9f\")\n" " invalid\n" "}\n" "\n" @@ -138,9 +152,104 @@ BOOST_AUTO_TEST_CASE(all_assembly_items) "{\"begin\":1,\"end\":3,\"name\":\"PUSH #[$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"}," "{\"begin\":1,\"end\":3,\"name\":\"PUSH [$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"}," "{\"begin\":1,\"end\":3,\"name\":\"PUSHDEPLOYADDRESS\",\"source\":0}," + "{\"begin\":1,\"end\":3,\"name\":\"ASSIGNIMMUTABLE\",\"source\":0,\"value\":\"someOtherImmutable\"}," + "{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"2\"}," + "{\"begin\":1,\"end\":3,\"name\":\"ASSIGNIMMUTABLE\",\"source\":0,\"value\":\"someImmutable\"}," "{\"begin\":1,\"end\":3,\"name\":\"STOP\",\"source\":0}" - "],\".data\":{\"0\":{\".code\":[{\"begin\":6,\"end\":8,\"name\":\"INVALID\",\"source\":1}]}," - "\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\":\"01020304\"}}" + "],\".data\":{\"0\":{\".code\":[" + "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}," + "{\"begin\":6,\"end\":8,\"name\":\"INVALID\",\"source\":1}" + "]},\"A6885B3731702DA62E8E4A8F584AC46A7F6822F4E2BA50FBA902F67B1588D23B\":\"01020304\"}}" + ); +} + +BOOST_AUTO_TEST_CASE(immutable) +{ + map indices = { + { "root.asm", 0 }, + { "sub.asm", 1 } + }; + Assembly _assembly; + auto root_asm = make_shared("lorem ipsum", "root.asm"); + _assembly.setSourceLocation({1, 3, root_asm}); + + Assembly _subAsm; + auto sub_asm = make_shared("lorem ipsum", "sub.asm"); + _subAsm.setSourceLocation({6, 8, sub_asm}); + _subAsm.appendImmutable("someImmutable"); + _subAsm.appendImmutable("someOtherImmutable"); + _subAsm.appendImmutable("someImmutable"); + shared_ptr _subAsmPtr = make_shared(_subAsm); + + _assembly.append(u256(42)); + _assembly.appendImmutableAssignment("someImmutable"); + _assembly.append(u256(23)); + _assembly.appendImmutableAssignment("someOtherImmutable"); + + auto sub = _assembly.appendSubroutine(_subAsmPtr); + _assembly.pushSubroutineOffset(size_t(sub.data())); + + checkCompilation(_assembly); + + BOOST_CHECK_EQUAL( + _assembly.assemble().toHex(), + // root.asm + // assign "someImmutable" + "602a" // PUSH1 42 - value for someImmutable + "80" // DUP1 + "6001" // PUSH1 1 - offset of first someImmutable in sub_0 + "52" // MSTORE + "80" // DUP1 + "6043" // PUSH1 67 - offset of second someImmutable in sub_0 + "52" // MSTORE + "50" // POP + // assign "someOtherImmutable" + "6017" // PUSH1 23 - value for someOtherImmutable + "80" // DUP1 + "6022" // PUSH1 34 - offset of someOtherImmutable in sub_0 + "52" // MSTORE + "50" // POP + "6063" // PUSH1 0x63 - dataSize(sub_0) + "6017" // PUSH1 0x17 - dataOffset(sub_0) + "fe" // INVALID + // end of root.asm + // sub.asm + "7f0000000000000000000000000000000000000000000000000000000000000000" // PUSHIMMUTABLE someImmutable - data at offset 1 + "7f0000000000000000000000000000000000000000000000000000000000000000" // PUSHIMMUTABLE someOtherImmutable - data at offset 34 + "7f0000000000000000000000000000000000000000000000000000000000000000" // PUSHIMMUTABLE someImmutable - data at offset 67 + ); + BOOST_CHECK_EQUAL( + _assembly.assemblyString(), + " /* \"root.asm\":1:3 */\n" + " 0x2a\n" + " assignImmutable(\"0x26f2c0195e9d408feff3abd77d83f2971f3c9a18d1e8a9437c7835ae4211fc9f\")\n" + " 0x17\n" + " assignImmutable(\"0xc3978657661c4d8e32e3d5f42597c009f0d3859e9f9d0d94325268f9799e2bfb\")\n" + " dataSize(sub_0)\n" + " dataOffset(sub_0)\n" + "stop\n" + "\n" + "sub_0: assembly {\n" + " /* \"sub.asm\":6:8 */\n" + " immutable(\"0x26f2c0195e9d408feff3abd77d83f2971f3c9a18d1e8a9437c7835ae4211fc9f\")\n" + " immutable(\"0xc3978657661c4d8e32e3d5f42597c009f0d3859e9f9d0d94325268f9799e2bfb\")\n" + " immutable(\"0x26f2c0195e9d408feff3abd77d83f2971f3c9a18d1e8a9437c7835ae4211fc9f\")\n" + "}\n" + ); + BOOST_CHECK_EQUAL( + util::jsonCompactPrint(_assembly.assemblyJSON(indices)), + "{\".code\":[" + "{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"2A\"}," + "{\"begin\":1,\"end\":3,\"name\":\"ASSIGNIMMUTABLE\",\"source\":0,\"value\":\"someImmutable\"}," + "{\"begin\":1,\"end\":3,\"name\":\"PUSH\",\"source\":0,\"value\":\"17\"}," + "{\"begin\":1,\"end\":3,\"name\":\"ASSIGNIMMUTABLE\",\"source\":0,\"value\":\"someOtherImmutable\"}," + "{\"begin\":1,\"end\":3,\"name\":\"PUSH #[$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"}," + "{\"begin\":1,\"end\":3,\"name\":\"PUSH [$]\",\"source\":0,\"value\":\"0000000000000000000000000000000000000000000000000000000000000000\"}" + "],\".data\":{\"0\":{\".code\":[" + "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}," + "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someOtherImmutable\"}," + "{\"begin\":6,\"end\":8,\"name\":\"PUSHIMMUTABLE\",\"source\":1,\"value\":\"someImmutable\"}" + "]}}}" ); } diff --git a/test/libsolidity/semanticTests/immutable/external_function_pointer.sol b/test/libsolidity/semanticTests/immutable/external_function_pointer.sol index f671065ace8e..c815a18c3d20 100644 --- a/test/libsolidity/semanticTests/immutable/external_function_pointer.sol +++ b/test/libsolidity/semanticTests/immutable/external_function_pointer.sol @@ -1,20 +1,20 @@ contract D { - function f() external view returns (uint256) { - return 42; - } + function f() external view returns (uint256) { + return 42; + } } contract C { - D d; - function() external view returns(uint256) immutable z; - constructor() public { - d = new D(); - z = d.f; - } - function f() public view returns (uint256) { + D d; + function() external view returns(uint256) immutable z; + constructor() public { + d = new D(); + z = d.f; + } + function f() public view returns (uint256) { assert(z.address == address(d)); assert(z.selector == D.f.selector); - return z(); - } + return z(); + } } // ---- // f() -> 42 diff --git a/test/libsolidity/semanticTests/immutable/inheritance.sol b/test/libsolidity/semanticTests/immutable/inheritance.sol new file mode 100644 index 000000000000..f61009f60040 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/inheritance.sol @@ -0,0 +1,30 @@ +contract A { + uint8 immutable a; + constructor() public { + a = 4; + } +} +contract B is A { + uint8 immutable b; + constructor() public { + b = 3; + } +} +contract C is A { + uint8 immutable c; + constructor() public { + c = 2; + } +} +contract D is B, C { + uint8 immutable d; + + constructor() public { + d = 1; + } + function f() public view returns (uint256, uint256, uint, uint) { + return (a, b, c, d); + } +} +// ---- +// f() -> 4, 3, 2, 1 diff --git a/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol new file mode 100644 index 000000000000..0673aafb5672 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/internal_function_pointer.sol @@ -0,0 +1,15 @@ +contract C { + function() internal view returns(uint256) immutable z; + constructor() public { + z = f; + } + function f() public view returns (uint256) { + return 7; + } + function callZ() public view returns (uint) { + return z(); + } +} +// ---- +// f() -> 7 +// callZ() -> 7 diff --git a/test/libsolidity/semanticTests/immutable/multi_creation.sol b/test/libsolidity/semanticTests/immutable/multi_creation.sol new file mode 100644 index 000000000000..b9e362dbd5ce --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/multi_creation.sol @@ -0,0 +1,31 @@ +contract A { + uint immutable a; + constructor() public { + a = 7; + } + function f() public view returns (uint) { return a; } +} +contract B { + uint immutable a; + constructor() public { + a = 5; + } + function f() public view returns (uint) { return a; } +} +contract C { + uint immutable a; + uint public x; + uint public y; + constructor() public { + a = 3; + x = (new A()).f(); + y = (new B()).f(); + } + function f() public returns (uint256, uint, uint) { + return (a, (new A()).f(), (new B()).f()); + } +} +// ---- +// f() -> 3, 7, 5 +// x() -> 7 +// y() -> 5 diff --git a/test/libsolidity/semanticTests/immutable/read_during_creation.sol b/test/libsolidity/semanticTests/immutable/read_during_creation.sol deleted file mode 100644 index 4a037cadceae..000000000000 --- a/test/libsolidity/semanticTests/immutable/read_during_creation.sol +++ /dev/null @@ -1,13 +0,0 @@ -contract C { - uint256 immutable x; - uint256 immutable y; - constructor() public { - x = 42; - y = x; - } - function f() public view returns (uint256, uint256) { - return (x+x,y); - } -} -// ---- -// f() -> 84, 42 diff --git a/test/libsolidity/semanticTests/immutable/stub.sol b/test/libsolidity/semanticTests/immutable/stub.sol index ee9ed0678c44..387541066e56 100644 --- a/test/libsolidity/semanticTests/immutable/stub.sol +++ b/test/libsolidity/semanticTests/immutable/stub.sol @@ -1,13 +1,13 @@ contract C { - uint256 immutable x; - uint256 immutable y; - constructor() public { - x = 42; - y = 23; - } - function f() public view returns (uint256, uint256) { - return (x+x,y); - } + uint256 immutable x; + uint256 immutable y; + constructor() public { + x = 42; + y = 23; + } + function f() public view returns (uint256, uint256) { + return (x+x,y); + } } // ---- // f() -> 84, 23 diff --git a/test/libsolidity/semanticTests/immutable/use_scratch.sol b/test/libsolidity/semanticTests/immutable/use_scratch.sol new file mode 100644 index 000000000000..d83da476d423 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/use_scratch.sol @@ -0,0 +1,19 @@ +contract C { + uint256 immutable x; + uint256 immutable y; + mapping(uint => uint) public m; + constructor(uint _a) public { + x = 42; + y = 23; + m[_a] = 7; + new uint[](4); + + } + function f() public view returns (uint256, uint256) { + return (x+x,y); + } +} +// ---- +// constructor(): 3 -> +// f() -> 84, 23 +// m(uint256): 3 -> 7 From 8b443627e29d1e06ae7b3892be4645de648deb2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 19:28:58 +0100 Subject: [PATCH 103/165] [yul-phaser] Add ProgramCache class --- test/CMakeLists.txt | 2 + test/yulPhaser/ProgramCache.cpp | 207 +++++++++++++++++++++++++++++++ tools/CMakeLists.txt | 2 + tools/yulPhaser/ProgramCache.cpp | 94 ++++++++++++++ tools/yulPhaser/ProgramCache.h | 91 ++++++++++++++ 5 files changed, 396 insertions(+) create mode 100644 test/yulPhaser/ProgramCache.cpp create mode 100644 tools/yulPhaser/ProgramCache.cpp create mode 100644 tools/yulPhaser/ProgramCache.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 181a0fbcf9dd..d63d9aec5f81 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -154,6 +154,7 @@ set(yul_phaser_sources yulPhaser/Phaser.cpp yulPhaser/Population.cpp yulPhaser/Program.cpp + yulPhaser/ProgramCache.cpp yulPhaser/Selections.cpp yulPhaser/SimulationRNG.cpp @@ -170,6 +171,7 @@ set(yul_phaser_sources ../tools/yulPhaser/Phaser.cpp ../tools/yulPhaser/Population.cpp ../tools/yulPhaser/Program.cpp + ../tools/yulPhaser/ProgramCache.cpp ../tools/yulPhaser/Selections.cpp ../tools/yulPhaser/SimulationRNG.cpp ) diff --git a/test/yulPhaser/ProgramCache.cpp b/test/yulPhaser/ProgramCache.cpp new file mode 100644 index 000000000000..598e7a16fba9 --- /dev/null +++ b/test/yulPhaser/ProgramCache.cpp @@ -0,0 +1,207 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include +#include + +#include + +#include + +#include + +#include +#include + +using namespace std; +using namespace solidity::util; +using namespace solidity::langutil; +using namespace solidity::yul; + +namespace solidity::phaser::test +{ + +class ProgramCacheFixture +{ +protected: + static constexpr char SampleSourceCode[] = + "{\n" + " for { let i := 0 } not(eq(i, 15)) { i := add(i, 1) }\n" + " {\n" + " let x := 1\n" + " mstore(i, 2)\n" + " }\n" + "}\n"; + + Program optimisedProgram(Program _program, string _abbreviatedOptimisationSteps) const + { + Program result = move(_program); + result.optimise(Chromosome(_abbreviatedOptimisationSteps).optimisationSteps()); + return result; + } + + static set cachedKeys(ProgramCache const& _programCache) + { + set keys; + for (auto pair = _programCache.entries().begin(); pair != _programCache.entries().end(); ++pair) + keys.insert(pair->first); + + return keys; + } + + CharStream m_sourceStream = CharStream(SampleSourceCode, "program-cache-test"); + Program m_program = get(Program::load(m_sourceStream)); + ProgramCache m_programCache{m_program}; +}; + +BOOST_AUTO_TEST_SUITE(Phaser) +BOOST_AUTO_TEST_SUITE(ProgramCacheTest) + +BOOST_FIXTURE_TEST_CASE(optimiseProgram_should_apply_optimisation_steps_to_program, ProgramCacheFixture) +{ + Program expectedProgram = optimisedProgram(m_program, "IuO"); + assert(toString(expectedProgram) != toString(m_program)); + + Program cachedProgram = m_programCache.optimiseProgram("IuO"); + + BOOST_TEST(toString(cachedProgram) == toString(expectedProgram)); +} + +BOOST_FIXTURE_TEST_CASE(optimiseProgram_should_store_programs_for_all_prefixes, ProgramCacheFixture) +{ + Program programI = optimisedProgram(m_program, "I"); + Program programIu = optimisedProgram(programI, "u"); + Program programIuO = optimisedProgram(programIu, "O"); + assert(toString(m_program) != toString(programI)); + assert(toString(m_program) != toString(programIu)); + assert(toString(m_program) != toString(programIuO)); + assert(toString(programI) != toString(programIu)); + assert(toString(programI) != toString(programIuO)); + assert(toString(programIu) != toString(programIuO)); + + BOOST_REQUIRE(m_programCache.size() == 0); + + Program cachedProgram = m_programCache.optimiseProgram("IuO"); + + BOOST_TEST(toString(cachedProgram) == toString(programIuO)); + + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "IuO"})); + BOOST_TEST(toString(*m_programCache.find("I")) == toString(programI)); + BOOST_TEST(toString(*m_programCache.find("Iu")) == toString(programIu)); + BOOST_TEST(toString(*m_programCache.find("IuO")) == toString(programIuO)); +} + +BOOST_FIXTURE_TEST_CASE(optimiseProgram_should_repeat_the_chromosome_requested_number_of_times, ProgramCacheFixture) +{ + string steps = "IuOIuO"; + + Program cachedProgram = m_programCache.optimiseProgram("IuO", 2); + + ProgramCache cacheNoRepetitions(m_program); + Program cachedProgramNoRepetitions = cacheNoRepetitions.optimiseProgram("IuOIuO"); + + BOOST_TEST(toString(cachedProgram) == toString(cachedProgramNoRepetitions)); + + for (size_t size = 1; size <= 6; ++size) + { + BOOST_REQUIRE(m_programCache.contains(steps.substr(0, size))); + BOOST_REQUIRE(cacheNoRepetitions.contains(steps.substr(0, size))); + BOOST_TEST( + toString(*cacheNoRepetitions.find(steps.substr(0, size))) == + toString(*m_programCache.find(steps.substr(0, size))) + ); + } +} + +BOOST_FIXTURE_TEST_CASE(optimiseProgram_should_reuse_the_longest_prefix_and_move_it_to_the_next_round, ProgramCacheFixture) +{ + BOOST_TEST(m_programCache.currentRound() == 0); + + m_programCache.optimiseProgram("Iu"); + m_programCache.optimiseProgram("Ia"); + m_programCache.startRound(1); + + BOOST_TEST(m_programCache.currentRound() == 1); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "Ia"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Ia")->second.roundNumber == 0); + + m_programCache.optimiseProgram("IuOI"); + + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "Ia", "IuO", "IuOI"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 1); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 1); + BOOST_TEST(m_programCache.entries().find("Ia")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("IuO")->second.roundNumber == 1); + BOOST_TEST(m_programCache.entries().find("IuOI")->second.roundNumber == 1); +} + +BOOST_FIXTURE_TEST_CASE(startRound_should_remove_entries_older_than_two_rounds, ProgramCacheFixture) +{ + BOOST_TEST(m_programCache.currentRound() == 0); + BOOST_TEST(m_programCache.size() == 0); + + m_programCache.optimiseProgram("Iu"); + + BOOST_TEST(m_programCache.currentRound() == 0); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 0); + + m_programCache.optimiseProgram("a"); + + BOOST_TEST(m_programCache.currentRound() == 0); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "a"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("a")->second.roundNumber == 0); + + m_programCache.startRound(1); + + BOOST_TEST(m_programCache.currentRound() == 1); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "a"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("a")->second.roundNumber == 0); + + m_programCache.optimiseProgram("af"); + + BOOST_TEST(m_programCache.currentRound() == 1); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "a", "af"})); + BOOST_TEST(m_programCache.entries().find("I")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("Iu")->second.roundNumber == 0); + BOOST_TEST(m_programCache.entries().find("a")->second.roundNumber == 1); + BOOST_TEST(m_programCache.entries().find("af")->second.roundNumber == 1); + + m_programCache.startRound(2); + + BOOST_TEST(m_programCache.currentRound() == 2); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"a", "af"})); + BOOST_TEST(m_programCache.entries().find("a")->second.roundNumber == 1); + BOOST_TEST(m_programCache.entries().find("af")->second.roundNumber == 1); + + m_programCache.startRound(3); + + BOOST_TEST(m_programCache.currentRound() == 3); + BOOST_TEST(m_programCache.size() == 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index fd5f92bbe1ef..241a80f46e89 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -35,6 +35,8 @@ add_executable(yul-phaser yulPhaser/PairSelections.cpp yulPhaser/Selections.h yulPhaser/Selections.cpp + yulPhaser/ProgramCache.h + yulPhaser/ProgramCache.cpp yulPhaser/Program.h yulPhaser/Program.cpp yulPhaser/SimulationRNG.h diff --git a/tools/yulPhaser/ProgramCache.cpp b/tools/yulPhaser/ProgramCache.cpp new file mode 100644 index 000000000000..bd3b05114c96 --- /dev/null +++ b/tools/yulPhaser/ProgramCache.cpp @@ -0,0 +1,94 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +using namespace std; +using namespace solidity::yul; +using namespace solidity::phaser; + +Program ProgramCache::optimiseProgram( + string const& _abbreviatedOptimisationSteps, + size_t _repetitionCount +) +{ + string targetOptimisations = _abbreviatedOptimisationSteps; + for (size_t i = 1; i < _repetitionCount; ++i) + targetOptimisations += _abbreviatedOptimisationSteps; + + size_t prefixSize = 0; + for (size_t i = 1; i <= targetOptimisations.size(); ++i) + { + auto const& pair = m_entries.find(targetOptimisations.substr(0, i)); + if (pair != m_entries.end()) + { + pair->second.roundNumber = m_currentRound; + ++prefixSize; + } + else + break; + } + + Program intermediateProgram = ( + prefixSize == 0 ? + m_program : + m_entries.at(targetOptimisations.substr(0, prefixSize)).program + ); + + for (size_t i = prefixSize + 1; i <= targetOptimisations.size(); ++i) + { + string stepName = OptimiserSuite::stepAbbreviationToNameMap().at(targetOptimisations[i - 1]); + intermediateProgram.optimise({stepName}); + + m_entries.insert({targetOptimisations.substr(0, i), {intermediateProgram, m_currentRound}}); + } + + return intermediateProgram; +} + +void ProgramCache::startRound(size_t _roundNumber) +{ + assert(_roundNumber > m_currentRound); + m_currentRound = _roundNumber; + + for (auto pair = m_entries.begin(); pair != m_entries.end();) + { + assert(pair->second.roundNumber < m_currentRound); + + if (pair->second.roundNumber < m_currentRound - 1) + m_entries.erase(pair++); + else + ++pair; + } +} + +void ProgramCache::clear() +{ + m_entries.clear(); + m_currentRound = 0; +} + +Program const* ProgramCache::find(string const& _abbreviatedOptimisationSteps) const +{ + auto const& pair = m_entries.find(_abbreviatedOptimisationSteps); + if (pair == m_entries.end()) + return nullptr; + + return &(pair->second.program); +} diff --git a/tools/yulPhaser/ProgramCache.h b/tools/yulPhaser/ProgramCache.h new file mode 100644 index 000000000000..433ba99c5ec9 --- /dev/null +++ b/tools/yulPhaser/ProgramCache.h @@ -0,0 +1,91 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#pragma once + +#include + +#include +#include + +namespace solidity::phaser +{ + +/** + * Structure used by @a ProgramCache to store intermediate programs and metadata associated + * with them. + */ +struct CacheEntry +{ + Program program; + size_t roundNumber; + + CacheEntry(Program _program, size_t _roundNumber): + program(std::move(_program)), + roundNumber(_roundNumber) {} +}; + +/** + * Class that optimises programs one step at a time which allows it to store and later reuse the + * results of the intermediate steps. + * + * The cache keeps track of the current round number and associates newly created entries with it. + * @a startRound() must be called at the beginning of a round so that entries that are too old + * can be purged. The current strategy is to store programs corresponding to all possible prefixes + * encountered in the current and the previous rounds. Entries older than that get removed to + * conserve memory. + * + * The current strategy does speed things up (about 4:1 hit:miss ratio observed in my limited + * experiments) but there's room for improvement. We could fit more useful programs in + * the cache by being more picky about which ones we choose. + * + * There is currently no way to purge entries without starting a new round. Since the programs + * take a lot of memory, this may lead to the cache eating up all the available RAM if sequences are + * long and programs large. A limiter based on entry count or total program size would be useful. + */ +class ProgramCache +{ +public: + explicit ProgramCache(Program _program): + m_program(std::move(_program)) {} + + Program optimiseProgram( + std::string const& _abbreviatedOptimisationSteps, + size_t _repetitionCount = 1 + ); + void startRound(size_t _nextRoundNumber); + void clear(); + + size_t size() const { return m_entries.size(); } + Program const* find(std::string const& _abbreviatedOptimisationSteps) const; + bool contains(std::string const& _abbreviatedOptimisationSteps) const { return find(_abbreviatedOptimisationSteps) != nullptr; } + + std::map const& entries() const { return m_entries; }; + Program const& program() const { return m_program; } + size_t currentRound() const { return m_currentRound; } + +private: + // The best matching data structure here would be a trie of chromosome prefixes but since + // the programs are orders of magnitude larger than the prefixes, it does not really matter. + // A map should be good enough. + std::map m_entries; + + Program m_program; + size_t m_currentRound = 0; +}; + +} From 259f738f172b9637c2a6f4558604328fe8fa58eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 20:55:13 +0100 Subject: [PATCH 104/165] [yul-phaser] ProgramBasedMetric: Add the ability to use ProgramCache --- test/yulPhaser/FitnessMetrics.cpp | 78 +++++++++++++++++++++++------- tools/yulPhaser/FitnessMetrics.cpp | 26 +++++++++- tools/yulPhaser/FitnessMetrics.h | 29 +++++++---- tools/yulPhaser/Phaser.cpp | 2 + 4 files changed, 106 insertions(+), 29 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 8b62b03b7e0c..524ef6357e1f 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -76,15 +76,16 @@ class ProgramBasedMetricFixture Chromosome m_chromosome{vector{UnusedPruner::name, EquivalentFunctionCombiner::name}}; Program m_program = get(Program::load(m_sourceStream)); Program m_optimisedProgram = optimisedProgram(m_program); + shared_ptr m_programCache = make_shared(m_program); }; class FitnessMetricCombinationFixture: public ProgramBasedMetricFixture { protected: vector> m_simpleMetrics = { - make_shared(m_program, 1), - make_shared(m_program, 2), - make_shared(m_program, 3), + make_shared(m_program, nullptr, 1), + make_shared(m_program, nullptr, 2), + make_shared(m_program, nullptr, 3), }; vector m_fitness = { m_simpleMetrics[0]->evaluate(m_chromosome), @@ -97,31 +98,66 @@ BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(FitnessMetricsTest) BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest) -BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program, ProgramBasedMetricFixture) +BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program_even_if_cache_not_available, ProgramBasedMetricFixture) { - string code = toString(DummyProgramBasedMetric(m_program).optimisedProgram(m_chromosome)); + string code = toString(DummyProgramBasedMetric(m_program, nullptr).optimisedProgram(m_chromosome)); BOOST_TEST(code != toString(m_program)); BOOST_TEST(code == toString(m_optimisedProgram)); } +BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_use_cache_if_available, ProgramBasedMetricFixture) +{ + string code = toString(DummyProgramBasedMetric(nullopt, m_programCache).optimisedProgram(m_chromosome)); + + BOOST_TEST(code != toString(m_program)); + BOOST_TEST(code == toString(m_optimisedProgram)); + BOOST_TEST(m_programCache->size() == m_chromosome.length()); +} + +BOOST_FIXTURE_TEST_CASE(optimisedProgramNoCache_should_return_optimised_program_even_if_cache_not_available, ProgramBasedMetricFixture) +{ + string code = toString(DummyProgramBasedMetric(m_program, nullptr).optimisedProgramNoCache(m_chromosome)); + + BOOST_TEST(code != toString(m_program)); + BOOST_TEST(code == toString(m_optimisedProgram)); +} + +BOOST_FIXTURE_TEST_CASE(optimisedProgramNoCache_should_not_use_cache_even_if_available, ProgramBasedMetricFixture) +{ + string code = toString(DummyProgramBasedMetric(nullopt, m_programCache).optimisedProgramNoCache(m_chromosome)); + + BOOST_TEST(code != toString(m_program)); + BOOST_TEST(code == toString(m_optimisedProgram)); + BOOST_TEST(m_programCache->size() == 0); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ProgramSizeTest) BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, ProgramBasedMetricFixture) { - size_t fitness = ProgramSize(m_program).evaluate(m_chromosome); + size_t fitness = ProgramSize(m_program, nullptr).evaluate(m_chromosome); BOOST_TEST(fitness != m_program.codeSize()); BOOST_TEST(fitness == m_optimisedProgram.codeSize()); } +BOOST_FIXTURE_TEST_CASE(evaluate_should_be_able_to_use_program_cache_if_available, ProgramBasedMetricFixture) +{ + size_t fitness = ProgramSize(nullopt, m_programCache).evaluate(m_chromosome); + + BOOST_TEST(fitness != m_program.codeSize()); + BOOST_TEST(fitness == m_optimisedProgram.codeSize()); + BOOST_TEST(m_programCache->size() == m_chromosome.length()); +} + BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) { Program const& programOptimisedOnce = m_optimisedProgram; Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); - ProgramSize metric(m_program, 2); + ProgramSize metric(m_program, nullptr, 2); size_t fitness = metric.evaluate(m_chromosome); BOOST_TEST(fitness != m_program.codeSize()); @@ -131,7 +167,7 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) { - ProgramSize metric(m_program, 0); + ProgramSize metric(m_program, nullptr, 0); size_t fitness = metric.evaluate(m_chromosome); BOOST_TEST(fitness == m_program.codeSize()); @@ -143,7 +179,13 @@ BOOST_AUTO_TEST_SUITE(RelativeProgramSizeTest) BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_the_size_ratio_between_optimised_program_and_original_program, ProgramBasedMetricFixture) { - BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize())); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize())); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_should_be_able_to_use_program_cache_if_available, ProgramBasedMetricFixture) +{ + BOOST_TEST(RelativeProgramSize(nullopt, m_programCache, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize())); + BOOST_TEST(m_programCache->size() == m_chromosome.length()); } BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number_of_times, ProgramBasedMetricFixture) @@ -151,17 +193,17 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number Program const& programOptimisedOnce = m_optimisedProgram; Program programOptimisedTwice = optimisedProgram(programOptimisedOnce); - RelativeProgramSize metric(m_program, 3, 2); + RelativeProgramSize metric(m_program, nullptr, 3, 2); size_t fitness = metric.evaluate(m_chromosome); BOOST_TEST(fitness != 1000); - BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, 3, 1).evaluate(m_chromosome)); + BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, nullptr, 3, 1).evaluate(m_chromosome)); BOOST_TEST(fitness == round(1000.0 * programOptimisedTwice.codeSize() / m_program.codeSize())); } BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture) { - RelativeProgramSize metric(m_program, 3, 0); + RelativeProgramSize metric(m_program, nullptr, 3, 0); BOOST_TEST(metric.evaluate(m_chromosome) == 1000); } @@ -171,7 +213,7 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_ CharStream sourceStream = CharStream("{}", ""); Program program = get(Program::load(sourceStream)); - RelativeProgramSize metric(program, 3); + RelativeProgramSize metric(program, nullptr, 3); BOOST_TEST(metric.evaluate(m_chromosome) == 1000); BOOST_TEST(metric.evaluate(Chromosome("")) == 1000); @@ -181,11 +223,11 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_ BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, ProgramBasedMetricFixture) { double sizeRatio = static_cast(m_optimisedProgram.codeSize()) / m_program.codeSize(); - BOOST_TEST(RelativeProgramSize(m_program, 0).evaluate(m_chromosome) == round(1.0 * sizeRatio)); - BOOST_TEST(RelativeProgramSize(m_program, 1).evaluate(m_chromosome) == round(10.0 * sizeRatio)); - BOOST_TEST(RelativeProgramSize(m_program, 2).evaluate(m_chromosome) == round(100.0 * sizeRatio)); - BOOST_TEST(RelativeProgramSize(m_program, 3).evaluate(m_chromosome) == round(1000.0 * sizeRatio)); - BOOST_TEST(RelativeProgramSize(m_program, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 0).evaluate(m_chromosome) == round(1.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 1).evaluate(m_chromosome) == round(10.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 2).evaluate(m_chromosome) == round(100.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 3).evaluate(m_chromosome) == round(1000.0 * sizeRatio)); + BOOST_TEST(RelativeProgramSize(m_program, nullptr, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/FitnessMetrics.cpp b/tools/yulPhaser/FitnessMetrics.cpp index 49482d0afe84..5279cea723f9 100644 --- a/tools/yulPhaser/FitnessMetrics.cpp +++ b/tools/yulPhaser/FitnessMetrics.cpp @@ -17,14 +17,36 @@ #include +#include + #include using namespace std; +using namespace solidity::util; using namespace solidity::phaser; -Program ProgramBasedMetric::optimisedProgram(Chromosome const& _chromosome) const +Program const& ProgramBasedMetric::program() const +{ + if (m_programCache == nullptr) + return m_program.value(); + else + return m_programCache->program(); +} + +Program ProgramBasedMetric::optimisedProgram(Chromosome const& _chromosome) +{ + if (m_programCache == nullptr) + return optimisedProgramNoCache(_chromosome); + + return m_programCache->optimiseProgram( + toString(_chromosome), + m_repetitionCount + ); +} + +Program ProgramBasedMetric::optimisedProgramNoCache(Chromosome const& _chromosome) const { - Program programCopy = m_program; + Program programCopy = program(); for (size_t i = 0; i < m_repetitionCount; ++i) programCopy.optimise(_chromosome.optimisationSteps()); diff --git a/tools/yulPhaser/FitnessMetrics.h b/tools/yulPhaser/FitnessMetrics.h index e79d99ff4c75..72e8111522c5 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -22,8 +22,10 @@ #include #include +#include #include +#include namespace solidity::phaser { @@ -50,7 +52,7 @@ class FitnessMetric * Abstract base class for fitness metrics that return values based on program size. * * The class provides utilities for optimising programs according to the information stored in - * chromosomes. + * chromosomes. Allows using @a ProgramCache. * * It can also store weights for the @a CodeSize metric. It does not do anything with * them because it does not actually compute the code size but they are readily available for use @@ -60,19 +62,27 @@ class ProgramBasedMetric: public FitnessMetric { public: explicit ProgramBasedMetric( - Program _program, + std::optional _program, + std::shared_ptr _programCache, size_t _repetitionCount = 1 ): m_program(std::move(_program)), - m_repetitionCount(_repetitionCount) {} - - Program const& program() const { return m_program; } + m_programCache(std::move(_programCache)), + m_repetitionCount(_repetitionCount) + { + assert(m_program.has_value() == (m_programCache == nullptr)); + } + + Program const& program() const; + ProgramCache const* programCache() const { return m_programCache.get(); } size_t repetitionCount() const { return m_repetitionCount; } - Program optimisedProgram(Chromosome const& _chromosome) const; + Program optimisedProgram(Chromosome const& _chromosome); + Program optimisedProgramNoCache(Chromosome const& _chromosome) const; private: - Program m_program; + std::optional m_program; + std::shared_ptr m_programCache; size_t m_repetitionCount; }; @@ -98,11 +108,12 @@ class RelativeProgramSize: public ProgramBasedMetric { public: explicit RelativeProgramSize( - Program _program, + std::optional _program, + std::shared_ptr _programCache, size_t _fixedPointPrecision, size_t _repetitionCount = 1 ): - ProgramBasedMetric(std::move(_program), _repetitionCount), + ProgramBasedMetric(std::move(_program), std::move(_programCache), _repetitionCount), m_fixedPointPrecision(_fixedPointPrecision) {} size_t fixedPointPrecision() const { return m_fixedPointPrecision; } diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index b29938f22f4e..cfe5cbd1ff50 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -171,6 +171,7 @@ unique_ptr FitnessMetricFactory::build( for (Program& program: _programs) metrics.push_back(make_unique( move(program), + nullptr, _options.chromosomeRepetitions )); @@ -181,6 +182,7 @@ unique_ptr FitnessMetricFactory::build( for (Program& program: _programs) metrics.push_back(make_unique( move(program), + nullptr, _options.relativeMetricScale, _options.chromosomeRepetitions )); From e2ff9698d39e766588d9d8d654d149f0e27bb112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 00:55:24 +0100 Subject: [PATCH 105/165] [yul-phaser] AlgorithmRunner: Add support for ProgramCache --- test/yulPhaser/AlgorithmRunner.cpp | 45 ++++++++++++++++++++++++----- tools/yulPhaser/AlgorithmRunner.cpp | 17 +++++++++++ tools/yulPhaser/AlgorithmRunner.h | 7 +++++ tools/yulPhaser/Phaser.cpp | 2 +- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 0b54ad38fa2f..0382cc90dfbf 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -29,6 +31,7 @@ using namespace std; using namespace boost::unit_test::framework; using namespace boost::test_tools; +using namespace solidity::langutil; using namespace solidity::util; namespace fs = boost::filesystem; @@ -92,7 +95,7 @@ BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRunnerFixture) { m_options.maxRounds = 5; - AlgorithmRunner runner(Population(m_fitnessMetric), m_options, m_output); + AlgorithmRunner runner(Population(m_fitnessMetric), {}, m_options, m_output); CountingAlgorithm algorithm; @@ -112,6 +115,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixt // NOTE: Chromosomes chosen so that they're not substrings of each other and are not // words likely to appear in the output in normal circumstances. Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), + {}, m_options, m_output ); @@ -131,7 +135,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_f { m_options.maxRounds = 0; m_options.populationAutosaveFile = m_autosavePath; - AlgorithmRunner runner(m_population, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); assert(!fs::exists(m_autosavePath)); runner.run(m_algorithm); @@ -145,7 +149,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_save_population_to_file_if_autosave_file_spec { m_options.maxRounds = 1; m_options.populationAutosaveFile = m_autosavePath; - AlgorithmRunner runner(m_population, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); assert(!fs::exists(m_autosavePath)); runner.run(m_algorithm); @@ -159,7 +163,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_overwrite_existing_file_if_autosave_file_spec { m_options.maxRounds = 5; m_options.populationAutosaveFile = m_autosavePath; - AlgorithmRunner runner(m_population, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); assert(!fs::exists(m_autosavePath)); vector originalContent = {"Original content"}; @@ -180,7 +184,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_save_population_to_file_if_autosave_file_ { m_options.maxRounds = 5; m_options.populationAutosaveFile = nullopt; - AlgorithmRunner runner(m_population, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); assert(!fs::exists(m_autosavePath)); runner.run(m_algorithm); @@ -198,7 +202,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_randomise_duplicate_chromosomes_if_requested, m_options.randomiseDuplicates = true; m_options.minChromosomeLength = 50; m_options.maxChromosomeLength = 50; - AlgorithmRunner runner(population, m_options, m_output); + AlgorithmRunner runner(population, {}, m_options, m_output); runner.run(algorithm); @@ -227,7 +231,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_randomise_duplicate_chromosomes_if_not_re m_options.maxRounds = 1; m_options.randomiseDuplicates = false; - AlgorithmRunner runner(population, m_options, m_output); + AlgorithmRunner runner(population, {}, m_options, m_output); runner.run(algorithm); @@ -237,6 +241,33 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_randomise_duplicate_chromosomes_if_not_re BOOST_TEST(runner.population().individuals()[2].chromosome == duplicate); } +BOOST_FIXTURE_TEST_CASE(run_should_clear_cache_at_the_beginning_and_update_it_before_each_round, AlgorithmRunnerFixture) +{ + CharStream sourceStream = CharStream("{}", current_test_case().p_name); + vector> caches = { + make_shared(get(Program::load(sourceStream))), + make_shared(get(Program::load(sourceStream))), + }; + + m_options.maxRounds = 10; + AlgorithmRunner runner(Population(m_fitnessMetric), caches, m_options, m_output); + CountingAlgorithm algorithm; + + BOOST_TEST(algorithm.m_currentRound == 0); + BOOST_TEST(caches[0]->currentRound() == 0); + BOOST_TEST(caches[1]->currentRound() == 0); + + runner.run(algorithm); + BOOST_TEST(algorithm.m_currentRound == 10); + BOOST_TEST(caches[0]->currentRound() == 10); + BOOST_TEST(caches[1]->currentRound() == 10); + + runner.run(algorithm); + BOOST_TEST(algorithm.m_currentRound == 20); + BOOST_TEST(caches[0]->currentRound() == 10); + BOOST_TEST(caches[1]->currentRound() == 10); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index b9f22171b813..e7ea5a072880 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -31,9 +31,12 @@ using namespace solidity::phaser; void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) { populationAutosave(); + cacheClear(); for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { + cacheStartRound(round + 1); + m_population = _algorithm.runNextRound(m_population); randomiseDuplicates(); @@ -66,6 +69,20 @@ void AlgorithmRunner::populationAutosave() const ); } +void AlgorithmRunner::cacheClear() +{ + for (auto& cache: m_programCaches) + if (cache != nullptr) + cache->clear(); +} + +void AlgorithmRunner::cacheStartRound(size_t _roundNumber) +{ + for (auto& cache: m_programCaches) + if (cache != nullptr) + cache->startRound(_roundNumber); +} + void AlgorithmRunner::randomiseDuplicates() { if (m_options.randomiseDuplicates) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index ff0d0e3c3bfc..8ee97ac485ff 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -50,10 +51,12 @@ class AlgorithmRunner AlgorithmRunner( Population _initialPopulation, + std::vector> _programCaches, Options _options, std::ostream& _outputStream ): m_population(std::move(_initialPopulation)), + m_programCaches(std::move(_programCaches)), m_options(std::move(_options)), m_outputStream(_outputStream) {} @@ -65,6 +68,9 @@ class AlgorithmRunner private: void populationAutosave() const; void randomiseDuplicates(); + void cacheClear(); + void cacheStartRound(size_t _roundNumber); + static Population randomiseDuplicates( Population _population, size_t _minChromosomeLength, @@ -72,6 +78,7 @@ class AlgorithmRunner ); Population m_population; + std::vector> m_programCaches; Options m_options; std::ostream& m_outputStream; }; diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index cfe5cbd1ff50..80aed022611e 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -577,6 +577,6 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) population.individuals().size() ); - AlgorithmRunner algorithmRunner(population, buildAlgorithmRunnerOptions(_arguments), cout); + AlgorithmRunner algorithmRunner(population, vector>(programs.size(), nullptr), buildAlgorithmRunnerOptions(_arguments), cout); algorithmRunner.run(*geneticAlgorithm); } From 3b49fbb8a56b9fec6d78af9f44131c103d62eba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Feb 2020 22:29:08 +0100 Subject: [PATCH 106/165] [yul-phaser] Add ProgramCacheFactory class --- test/yulPhaser/Phaser.cpp | 36 +++++++++++++++++++++++++++++++++++- tools/yulPhaser/Phaser.cpp | 19 +++++++++++++++++++ tools/yulPhaser/Phaser.h | 20 ++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index 04dfbe3dcb42..ca45c0771369 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -55,7 +55,7 @@ class GeneticAlgorithmFactoryFixture }; }; -class FitnessMetricFactoryFixture +class FixtureWithPrograms { protected: vector m_sourceStreams = { @@ -68,6 +68,11 @@ class FitnessMetricFactoryFixture get(Program::load(m_sourceStreams[1])), get(Program::load(m_sourceStreams[2])), }; +}; + +class FitnessMetricFactoryFixture: public FixtureWithPrograms +{ +protected: FitnessMetricFactory::Options m_options = { /* metric = */ MetricChoice::CodeSize, /* metricAggregator = */ MetricAggregatorChoice::Average, @@ -317,6 +322,35 @@ BOOST_FIXTURE_TEST_CASE(build_should_combine_populations_from_all_sources, Poula BOOST_TEST(count(begin, end, Individual(Chromosome("fcL"), *m_fitnessMetric)) >= 2); } + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(ProgramCacheFactoryTest) + +BOOST_FIXTURE_TEST_CASE(build_should_create_cache_for_each_input_program_if_cache_enabled, FixtureWithPrograms) +{ + ProgramCacheFactory::Options options{/* programCacheEnabled = */ true}; + vector> caches = ProgramCacheFactory::build(options, m_programs); + assert(m_programs.size() >= 2 && "There must be at least 2 programs for this test to be meaningful"); + + BOOST_TEST(caches.size() == m_programs.size()); + for (size_t i = 0; i < m_programs.size(); ++i) + { + BOOST_REQUIRE(caches[i] != nullptr); + BOOST_TEST(toString(caches[i]->program()) == toString(m_programs[i])); + } +} + +BOOST_FIXTURE_TEST_CASE(build_should_return_nullptr_for_each_input_program_if_cache_disabled, FixtureWithPrograms) +{ + ProgramCacheFactory::Options options{/* programCacheEnabled = */ false}; + vector> caches = ProgramCacheFactory::build(options, m_programs); + assert(m_programs.size() >= 2 && "There must be at least 2 programs for this test to be meaningful"); + + BOOST_TEST(caches.size() == m_programs.size()); + for (size_t i = 0; i < m_programs.size(); ++i) + BOOST_TEST(caches[i] == nullptr); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(ProgramFactoryTest) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 80aed022611e..054b6e99ee0b 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -283,6 +283,25 @@ Population PopulationFactory::buildFromFile( return buildFromStrings(readLinesFromFile(_filePath), move(_fitnessMetric)); } +ProgramCacheFactory::Options ProgramCacheFactory::Options::fromCommandLine(po::variables_map const& _arguments) +{ + return { + _arguments["program-cache"].as(), + }; +} + +vector> ProgramCacheFactory::build( + Options const& _options, + vector _programs +) +{ + vector> programCaches; + for (Program& program: _programs) + programCaches.push_back(_options.programCacheEnabled ? make_shared(move(program)) : nullptr); + + return programCaches; +} + ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_map const& _arguments) { return { diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 9814c9111f3b..256d9a28848e 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -45,6 +45,7 @@ class FitnessMetric; class GeneticAlgorithm; class Population; class Program; +class ProgramCache; enum class Algorithm { @@ -160,6 +161,25 @@ class PopulationFactory ); }; +/** + * Builds and validates instances of @a ProgramCache. + */ +class ProgramCacheFactory +{ +public: + struct Options + { + bool programCacheEnabled; + + static Options fromCommandLine(boost::program_options::variables_map const& _arguments); + }; + + static std::vector> build( + Options const& _options, + std::vector _programs + ); +}; + /** * Builds and validates instances of @a Program. */ From 98db50ccac95ba94be3352df8f7b2b57536031ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 26 Feb 2020 22:00:18 +0100 Subject: [PATCH 107/165] [yul-phaser] Add --program-cache option --- test/yulPhaser/Phaser.cpp | 37 +++++++++++++++++++++++++++++++++---- tools/yulPhaser/Phaser.cpp | 36 +++++++++++++++++++++++++++--------- tools/yulPhaser/Phaser.h | 3 ++- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/test/yulPhaser/Phaser.cpp b/test/yulPhaser/Phaser.cpp index ca45c0771369..633462865a23 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -159,7 +159,7 @@ BOOST_FIXTURE_TEST_CASE(build_should_create_metric_of_the_right_type, FitnessMet { m_options.metric = MetricChoice::RelativeCodeSize; m_options.metricAggregator = MetricAggregatorChoice::Sum; - unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}, {nullptr}); BOOST_REQUIRE(metric != nullptr); auto sumMetric = dynamic_cast(metric.get()); @@ -177,7 +177,7 @@ BOOST_FIXTURE_TEST_CASE(build_should_respect_chromosome_repetitions_option, Fitn m_options.metric = MetricChoice::CodeSize; m_options.metricAggregator = MetricAggregatorChoice::Average; m_options.chromosomeRepetitions = 5; - unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}, {nullptr}); BOOST_REQUIRE(metric != nullptr); auto averageMetric = dynamic_cast(metric.get()); @@ -195,7 +195,7 @@ BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFac m_options.metric = MetricChoice::RelativeCodeSize; m_options.metricAggregator = MetricAggregatorChoice::Average; m_options.relativeMetricScale = 10; - unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}); + unique_ptr metric = FitnessMetricFactory::build(m_options, {m_programs[0]}, {nullptr}); BOOST_REQUIRE(metric != nullptr); auto averageMetric = dynamic_cast(metric.get()); @@ -210,7 +210,11 @@ BOOST_FIXTURE_TEST_CASE(build_should_set_relative_metric_scale, FitnessMetricFac BOOST_FIXTURE_TEST_CASE(build_should_create_metric_for_each_input_program, FitnessMetricFactoryFixture) { - unique_ptr metric = FitnessMetricFactory::build(m_options, m_programs); + unique_ptr metric = FitnessMetricFactory::build( + m_options, + m_programs, + vector>(m_programs.size(), nullptr) + ); BOOST_REQUIRE(metric != nullptr); auto combinedMetric = dynamic_cast(metric.get()); @@ -218,6 +222,31 @@ BOOST_FIXTURE_TEST_CASE(build_should_create_metric_for_each_input_program, Fitne BOOST_REQUIRE(combinedMetric->metrics().size() == m_programs.size()); } +BOOST_FIXTURE_TEST_CASE(build_should_pass_program_caches_to_metrics, FitnessMetricFactoryFixture) +{ + assert(m_programs.size() == 3); + vector> caches = { + make_shared(m_programs[0]), + make_shared(m_programs[1]), + make_shared(m_programs[2]), + }; + + m_options.metric = MetricChoice::RelativeCodeSize; + unique_ptr metric = FitnessMetricFactory::build(m_options, m_programs, caches); + BOOST_REQUIRE(metric != nullptr); + + auto combinedMetric = dynamic_cast(metric.get()); + BOOST_REQUIRE(combinedMetric != nullptr); + BOOST_REQUIRE(combinedMetric->metrics().size() == caches.size()); + + for (size_t i = 0; i < caches.size(); ++i) + { + auto programBasedMetric = dynamic_cast(combinedMetric->metrics()[i].get()); + BOOST_REQUIRE(programBasedMetric != nullptr); + BOOST_TEST(programBasedMetric->programCache() == caches[i].get()); + } +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(PopulationFactoryTest) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 054b6e99ee0b..218b358a0230 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -158,9 +158,11 @@ FitnessMetricFactory::Options FitnessMetricFactory::Options::fromCommandLine(po: unique_ptr FitnessMetricFactory::build( Options const& _options, - vector _programs + vector _programs, + vector> _programCaches ) { + assert(_programCaches.size() == _programs.size()); assert(_programs.size() > 0 && "Validations should prevent this from being executed with zero files."); vector> metrics; @@ -168,10 +170,10 @@ unique_ptr FitnessMetricFactory::build( { case MetricChoice::CodeSize: { - for (Program& program: _programs) + for (size_t i = 0; i < _programs.size(); ++i) metrics.push_back(make_unique( - move(program), - nullptr, + _programCaches[i] != nullptr ? optional{} : move(_programs[i]), + move(_programCaches[i]), _options.chromosomeRepetitions )); @@ -179,10 +181,10 @@ unique_ptr FitnessMetricFactory::build( } case MetricChoice::RelativeCodeSize: { - for (Program& program: _programs) + for (size_t i = 0; i < _programs.size(); ++i) metrics.push_back(make_unique( - move(program), - nullptr, + _programCaches[i] != nullptr ? optional{} : move(_programs[i]), + move(_programCaches[i]), _options.relativeMetricScale, _options.chromosomeRepetitions )); @@ -528,6 +530,19 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ; keywordDescription.add(metricsDescription); + po::options_description cacheDescription("CACHE", lineLength, minDescriptionLength); + cacheDescription.add_options() + ( + "program-cache", + po::bool_switch(), + "Enables caching of intermediate programs corresponding to chromosome prefixes.\n" + "This speeds up fitness evaluation by a lot but eats tons of memory if the chromosomes are long. " + "Disabled by default since there's currently no way to set an upper limit on memory usage but " + "highly recommended if your computer has enough RAM." + ) + ; + keywordDescription.add(cacheDescription); + po::positional_options_description positionalDescription; positionalDescription.add("input-files", -1); @@ -583,12 +598,15 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c void Phaser::runAlgorithm(po::variables_map const& _arguments) { auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); + auto cacheOptions = ProgramCacheFactory::Options::fromCommandLine(_arguments); auto metricOptions = FitnessMetricFactory::Options::fromCommandLine(_arguments); auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments); auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); vector programs = ProgramFactory::build(programOptions); - unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs)); + vector> programCaches = ProgramCacheFactory::build(cacheOptions, programs); + + unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs), programCaches); Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( @@ -596,6 +614,6 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) population.individuals().size() ); - AlgorithmRunner algorithmRunner(population, vector>(programs.size(), nullptr), buildAlgorithmRunnerOptions(_arguments), cout); + AlgorithmRunner algorithmRunner(population, move(programCaches), buildAlgorithmRunnerOptions(_arguments), cout); algorithmRunner.run(*geneticAlgorithm); } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index 256d9a28848e..ba816044c46a 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -120,7 +120,8 @@ class FitnessMetricFactory static std::unique_ptr build( Options const& _options, - std::vector _programs + std::vector _programs, + std::vector> _programCaches ); }; From 339f3ca32c75aecdffb5e86534e50f23fc562355 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Tue, 24 Mar 2020 03:43:07 +0100 Subject: [PATCH 108/165] Fix #8427: Promoted typeError to fatalTypeError in ReferencesResolver::endVisit(UserDefinedTypeName). --- Changelog.md | 3 ++- libsolidity/analysis/ReferencesResolver.cpp | 2 +- .../syntaxTests/structs/member_type_eq_name.sol | 7 +++++++ test/libsolidity/syntaxTests/structs/member_type_func.sol | 8 ++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/syntaxTests/structs/member_type_eq_name.sol create mode 100644 test/libsolidity/syntaxTests/structs/member_type_func.sol diff --git a/Changelog.md b/Changelog.md index 2472d946712a..96f3a144484c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,7 +8,8 @@ Compiler Features: Bugfixes: - * Inline Assembly: Fix internal error when accessing incorrect constant variables. + * Inline Assembly: Fix internal error when accessing invalid constant variables. + * Reference Resolver: Fix internal error when accessing invalid struct members. * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. * JSON AST: Always add pointer suffix for memory reference types. diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 8ea07f1829cb..94a16d6f1552 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -204,7 +204,7 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName) else { _typeName.annotation().type = TypeProvider::emptyTuple(); - typeError(_typeName.location(), "Name has to refer to a struct, enum or contract."); + fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract."); } } diff --git a/test/libsolidity/syntaxTests/structs/member_type_eq_name.sol b/test/libsolidity/syntaxTests/structs/member_type_eq_name.sol new file mode 100644 index 000000000000..50f0eb365dc0 --- /dev/null +++ b/test/libsolidity/syntaxTests/structs/member_type_eq_name.sol @@ -0,0 +1,7 @@ +contract C { + struct S {t t;} + function f(function(S memory) external) public {} +} +// ---- +// TypeError: (25-26): Name has to refer to a struct, enum or contract. +// TypeError: (53-61): Internal type cannot be used for external function type. diff --git a/test/libsolidity/syntaxTests/structs/member_type_func.sol b/test/libsolidity/syntaxTests/structs/member_type_func.sol new file mode 100644 index 000000000000..709a40e267d7 --- /dev/null +++ b/test/libsolidity/syntaxTests/structs/member_type_func.sol @@ -0,0 +1,8 @@ +contract C { + function f() public {} + struct S {f x;} + function g(function(S memory) external) public {} +} +// ---- +// TypeError: (50-51): Name has to refer to a struct, enum or contract. +// TypeError: (78-86): Internal type cannot be used for external function type. From a97aeb0e6ee946ebf864534a29205bfd7fed15e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 8 Mar 2020 16:55:24 +0100 Subject: [PATCH 109/165] [yul-phaser] AlgorithmRunner: A stronger test for run() output --- test/yulPhaser/AlgorithmRunner.cpp | 55 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 0382cc90dfbf..ce6f43bd285f 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -28,6 +28,9 @@ #include #include +#include +#include + using namespace std; using namespace boost::unit_test::framework; using namespace boost::test_tools; @@ -65,8 +68,29 @@ class RandomisingAlgorithm: public GeneticAlgorithm class AlgorithmRunnerFixture { protected: + // NOTE: Regexes here should not contain spaces because we strip them before matching + regex RoundSummaryRegex{R"(-+ROUND\d+-+)"}; + + string individualPattern(Individual const& individual) const + { + ostringstream output; + output << "Fitness:" << individual.fitness << ","; + output << "optimisations:" << individual.chromosome; + return output.str(); + return output.str(); + } + + bool nextLineMatches(stringstream& stream, regex const& pattern) const + { + string line; + if (getline(stream, line).fail()) + return false; + + return regex_match(stripWhitespace(line), pattern); + } + shared_ptr m_fitnessMetric = make_shared(); - output_test_stream m_output; + stringstream m_output; AlgorithmRunner::Options m_options; }; @@ -106,29 +130,24 @@ BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRu BOOST_TEST(algorithm.m_currentRound == 10); } -BOOST_FIXTURE_TEST_CASE(run_should_print_the_top_chromosome, AlgorithmRunnerFixture) +BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, AlgorithmRunnerFixture) { - // run() is allowed to print more but should at least print the first one + Population population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}); m_options.maxRounds = 1; - AlgorithmRunner runner( - // NOTE: Chromosomes chosen so that they're not substrings of each other and are not - // words likely to appear in the output in normal circumstances. - Population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}), - {}, - m_options, - m_output - ); - - CountingAlgorithm algorithm; + AlgorithmRunner runner(population, {}, m_options, m_output); + RandomisingAlgorithm algorithm; - BOOST_TEST(m_output.is_empty()); - runner.run(algorithm); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 1); - runner.run(algorithm); runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, RoundSummaryRegex)); + for (auto const& individual: runner.population().individuals()) + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(individual)))); + runner.run(algorithm); - BOOST_TEST(countSubstringOccurrences(m_output.str(), toString(runner.population().individuals()[0].chromosome)) == 4); + BOOST_TEST(nextLineMatches(m_output, RoundSummaryRegex)); + for (auto const& individual: runner.population().individuals()) + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(individual)))); + BOOST_TEST(m_output.peek() == EOF); } BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) From d6b96063f8ed816d220fa28537ccd277cff2363a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sun, 8 Mar 2020 16:59:14 +0100 Subject: [PATCH 110/165] [yul-phaser] AlgorithmRunner: Make all tests use population from AlgorithmRunnerFixture --- test/yulPhaser/AlgorithmRunner.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index ce6f43bd285f..80a431fdcf73 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -90,6 +90,7 @@ class AlgorithmRunnerFixture } shared_ptr m_fitnessMetric = make_shared(); + Population const m_population = Population::makeRandom(m_fitnessMetric, 5, 0, 20); stringstream m_output; AlgorithmRunner::Options m_options; }; @@ -109,7 +110,6 @@ class AlgorithmRunnerAutosaveFixture: public AlgorithmRunnerFixture protected: TemporaryDirectory m_tempDir; string const m_autosavePath = m_tempDir.memberPath("population-autosave.txt"); - Population const m_population = Population::makeRandom(m_fitnessMetric, 5, 0, 20); RandomisingAlgorithm m_algorithm; }; @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_SUITE(AlgorithmRunnerTest) BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRunnerFixture) { m_options.maxRounds = 5; - AlgorithmRunner runner(Population(m_fitnessMetric), {}, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); CountingAlgorithm algorithm; @@ -132,10 +132,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRu BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, AlgorithmRunnerFixture) { - Population population(m_fitnessMetric, {Chromosome("fcCUnDve"), Chromosome("jsxIOo"), Chromosome("ighTLM")}); - m_options.maxRounds = 1; - AlgorithmRunner runner(population, {}, m_options, m_output); + AlgorithmRunner runner(m_population, {}, m_options, m_output); RandomisingAlgorithm algorithm; runner.run(algorithm); @@ -269,7 +267,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_clear_cache_at_the_beginning_and_update_it_be }; m_options.maxRounds = 10; - AlgorithmRunner runner(Population(m_fitnessMetric), caches, m_options, m_output); + AlgorithmRunner runner(m_population, caches, m_options, m_output); CountingAlgorithm algorithm; BOOST_TEST(algorithm.m_currentRound == 0); From ec10a3d378f9bf07a1c9e4d99a17c627929911a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 02:04:09 +0100 Subject: [PATCH 111/165] [yul-phaser] Add --show-initial-population option --- test/yulPhaser/AlgorithmRunner.cpp | 29 +++++++++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.cpp | 10 ++++++++++ tools/yulPhaser/AlgorithmRunner.h | 2 ++ tools/yulPhaser/Phaser.cpp | 11 +++++++++++ 4 files changed, 52 insertions(+) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 80a431fdcf73..8cd4ec803f9f 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -70,6 +70,7 @@ class AlgorithmRunnerFixture protected: // NOTE: Regexes here should not contain spaces because we strip them before matching regex RoundSummaryRegex{R"(-+ROUND\d+-+)"}; + regex InitialPopulationHeaderRegex{"-+INITIALPOPULATION-+"}; string individualPattern(Individual const& individual) const { @@ -133,6 +134,7 @@ BOOST_FIXTURE_TEST_CASE(run_should_call_runNextRound_once_per_round, AlgorithmRu BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, AlgorithmRunnerFixture) { m_options.maxRounds = 1; + m_options.showInitialPopulation = false; AlgorithmRunner runner(m_population, {}, m_options, m_output); RandomisingAlgorithm algorithm; @@ -148,6 +150,33 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, Algorit BOOST_TEST(m_output.peek() == EOF); } +BOOST_FIXTURE_TEST_CASE(run_should_print_initial_population_if_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 0; + m_options.showInitialPopulation = true; + RandomisingAlgorithm algorithm; + + AlgorithmRunner runner(m_population, {}, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(nextLineMatches(m_output, InitialPopulationHeaderRegex)); + for (auto const& individual: m_population.individuals()) + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(individual)))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_print_initial_population_if_not_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 0; + m_options.showInitialPopulation = false; + RandomisingAlgorithm algorithm; + + AlgorithmRunner runner(m_population, {}, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(m_output.peek() == EOF); +} + BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) { m_options.maxRounds = 0; diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index e7ea5a072880..dd1275daf791 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -31,6 +31,7 @@ using namespace solidity::phaser; void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) { populationAutosave(); + printInitialPopulation(); cacheClear(); for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) @@ -47,6 +48,15 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) } } +void AlgorithmRunner::printInitialPopulation() const +{ + if (!m_options.showInitialPopulation) + return; + + m_outputStream << "---------- INITIAL POPULATION ----------" << endl; + m_outputStream << m_population; +} + void AlgorithmRunner::populationAutosave() const { if (!m_options.populationAutosaveFile.has_value()) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 8ee97ac485ff..978c6a7cb4fc 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -47,6 +47,7 @@ class AlgorithmRunner bool randomiseDuplicates = false; std::optional minChromosomeLength = std::nullopt; std::optional maxChromosomeLength = std::nullopt; + bool showInitialPopulation = false; }; AlgorithmRunner( @@ -66,6 +67,7 @@ class AlgorithmRunner Population const& population() const { return m_population; } private: + void printInitialPopulation() const; void populationAutosave() const; void randomiseDuplicates(); void cacheClear(); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 218b358a0230..50cad1659312 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -543,6 +543,16 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() ; keywordDescription.add(cacheDescription); + po::options_description outputDescription("OUTPUT", lineLength, minDescriptionLength); + outputDescription.add_options() + ( + "show-initial-population", + po::bool_switch(), + "Print the state of the population before the algorithm starts." + ) + ; + keywordDescription.add(outputDescription); + po::positional_options_description positionalDescription; positionalDescription.add("input-files", -1); @@ -592,6 +602,7 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c !_arguments["no-randomise-duplicates"].as(), _arguments["min-chromosome-length"].as(), _arguments["max-chromosome-length"].as(), + _arguments["show-initial-population"].as(), }; } From c875b3d94468ef9199a5ceb6428cd5b540099e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 02:07:48 +0100 Subject: [PATCH 112/165] [yul-phaser] Add --show-only-top-chromosome and --hide-round options --- test/yulPhaser/AlgorithmRunner.cpp | 100 ++++++++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.cpp | 27 +++++++- tools/yulPhaser/AlgorithmRunner.h | 6 ++ tools/yulPhaser/Phaser.cpp | 12 ++++ 4 files changed, 143 insertions(+), 2 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 8cd4ec803f9f..b3379d66104e 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -78,6 +78,12 @@ class AlgorithmRunnerFixture output << "Fitness:" << individual.fitness << ","; output << "optimisations:" << individual.chromosome; return output.str(); + } + + string topChromosomePattern(size_t roundNumber, Individual const& individual) const + { + ostringstream output; + output << roundNumber << "\\|" << individualPattern(individual); return output.str(); } @@ -135,6 +141,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, Algorit { m_options.maxRounds = 1; m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = false; + m_options.showRoundInfo = true; AlgorithmRunner runner(m_population, {}, m_options, m_output); RandomisingAlgorithm algorithm; @@ -150,10 +158,83 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_round_summary_after_each_round, Algorit BOOST_TEST(m_output.peek() == EOF); } +BOOST_FIXTURE_TEST_CASE(run_should_not_print_round_summary_if_not_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = false; + m_options.showRoundInfo = false; + AlgorithmRunner runner(m_population, {}, m_options, m_output); + RandomisingAlgorithm algorithm; + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, regex(""))); + for (auto const& individual: runner.population().individuals()) + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(individual)))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_print_population_if_its_empty, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = false; + m_options.showRoundInfo = true; + AlgorithmRunner runner(Population(m_fitnessMetric), {}, m_options, m_output); + RandomisingAlgorithm algorithm; + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, RoundSummaryRegex)); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_only_top_chromosome_if_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = true; + m_options.showRoundInfo = true; + AlgorithmRunner runner(m_population, {}, m_options, m_output); + RandomisingAlgorithm algorithm; + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, regex(topChromosomePattern(1, runner.population().individuals()[0])))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_print_round_number_for_top_chromosome_if_round_info_not_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = true; + m_options.showRoundInfo = false; + AlgorithmRunner runner(m_population, {}, m_options, m_output); + RandomisingAlgorithm algorithm; + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(runner.population().individuals()[0])))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_not_print_population_if_its_empty_and_only_top_chromosome_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 3; + m_options.showRoundInfo = true; + m_options.showInitialPopulation = false; + m_options.showOnlyTopChromosome = true; + AlgorithmRunner runner(Population(m_fitnessMetric), {}, m_options, m_output); + RandomisingAlgorithm algorithm; + + runner.run(algorithm); + BOOST_TEST(m_output.peek() == EOF); +} + BOOST_FIXTURE_TEST_CASE(run_should_print_initial_population_if_requested, AlgorithmRunnerFixture) { m_options.maxRounds = 0; m_options.showInitialPopulation = true; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = false; RandomisingAlgorithm algorithm; AlgorithmRunner runner(m_population, {}, m_options, m_output); @@ -169,6 +250,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_print_initial_population_if_not_requested { m_options.maxRounds = 0; m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = false; RandomisingAlgorithm algorithm; AlgorithmRunner runner(m_population, {}, m_options, m_output); @@ -177,6 +260,23 @@ BOOST_FIXTURE_TEST_CASE(run_should_not_print_initial_population_if_not_requested BOOST_TEST(m_output.peek() == EOF); } +BOOST_FIXTURE_TEST_CASE(run_should_print_whole_initial_population_even_if_only_top_chromosome_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 0; + m_options.showInitialPopulation = true; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + RandomisingAlgorithm algorithm; + + AlgorithmRunner runner(m_population, {}, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(nextLineMatches(m_output, InitialPopulationHeaderRegex)); + for (auto const& individual: m_population.individuals()) + BOOST_TEST(nextLineMatches(m_output, regex(individualPattern(individual)))); + BOOST_TEST(m_output.peek() == EOF); +} + BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) { m_options.maxRounds = 0; diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index dd1275daf791..90440e120e9d 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -41,10 +41,33 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) m_population = _algorithm.runNextRound(m_population); randomiseDuplicates(); - m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; + printRoundSummary(round); + populationAutosave(); + } +} + +void AlgorithmRunner::printRoundSummary( + size_t _round +) const +{ + if (!m_options.showOnlyTopChromosome) + { + if (m_options.showRoundInfo) + { + m_outputStream << "---------- ROUND " << _round + 1; + m_outputStream << " ----------" << endl; + } + else if (m_population.individuals().size() > 0) + m_outputStream << endl; + m_outputStream << m_population; + } + else if (m_population.individuals().size() > 0) + { + if (m_options.showRoundInfo) + m_outputStream << setw(5) << _round + 1 << " | "; - populationAutosave(); + m_outputStream << m_population.individuals()[0] << endl; } } diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 978c6a7cb4fc..abef48869064 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -48,6 +49,8 @@ class AlgorithmRunner std::optional minChromosomeLength = std::nullopt; std::optional maxChromosomeLength = std::nullopt; bool showInitialPopulation = false; + bool showOnlyTopChromosome = false; + bool showRoundInfo = true; }; AlgorithmRunner( @@ -67,6 +70,9 @@ class AlgorithmRunner Population const& population() const { return m_population; } private: + void printRoundSummary( + size_t _round + ) const; void printInitialPopulation() const; void populationAutosave() const; void randomiseDuplicates(); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 50cad1659312..344b932082cb 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -550,6 +550,16 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::bool_switch(), "Print the state of the population before the algorithm starts." ) + ( + "show-only-top-chromosome", + po::bool_switch(), + "Print only the best chromosome found in each round rather than the whole population." + ) + ( + "hide-round", + po::bool_switch(), + "Hide information about the current round (round number and elapsed time)." + ) ; keywordDescription.add(outputDescription); @@ -603,6 +613,8 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c _arguments["min-chromosome-length"].as(), _arguments["max-chromosome-length"].as(), _arguments["show-initial-population"].as(), + _arguments["show-only-top-chromosome"].as(), + !_arguments["hide-round"].as(), }; } From 47c3b558f2fc399f27b9e9c478b413e1f073645b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 27 Feb 2020 02:08:40 +0100 Subject: [PATCH 113/165] [yul-phaser] AlgorithmRunner: Print elapsed time after each round --- test/yulPhaser/AlgorithmRunner.cpp | 2 +- tools/yulPhaser/AlgorithmRunner.cpp | 14 ++++++++++++-- tools/yulPhaser/AlgorithmRunner.h | 4 +++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index b3379d66104e..831cb360a41d 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -69,7 +69,7 @@ class AlgorithmRunnerFixture { protected: // NOTE: Regexes here should not contain spaces because we strip them before matching - regex RoundSummaryRegex{R"(-+ROUND\d+-+)"}; + regex RoundSummaryRegex{R"(-+ROUND\d+\[round:[0-9.]+s,total:[0-9.]+s\]-+)"}; regex InitialPopulationHeaderRegex{"-+INITIALPOPULATION-+"}; string individualPattern(Individual const& individual) const diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 90440e120e9d..9ddce41bce53 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -34,27 +34,37 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) printInitialPopulation(); cacheClear(); + chrono::steady_clock::time_point totalTimeStart = std::chrono::steady_clock::now(); for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { + chrono::steady_clock::time_point roundTimeStart = std::chrono::steady_clock::now(); cacheStartRound(round + 1); m_population = _algorithm.runNextRound(m_population); randomiseDuplicates(); - printRoundSummary(round); + printRoundSummary(round, roundTimeStart, totalTimeStart); populationAutosave(); } } void AlgorithmRunner::printRoundSummary( - size_t _round + size_t _round, + chrono::steady_clock::time_point _roundTimeStart, + chrono::steady_clock::time_point _totalTimeStart ) const { if (!m_options.showOnlyTopChromosome) { if (m_options.showRoundInfo) { + chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + auto roundTime = chrono::duration_cast(now - _roundTimeStart).count(); + auto totalTime = chrono::duration_cast(now - _totalTimeStart).count(); + m_outputStream << "---------- ROUND " << _round + 1; + m_outputStream << " [round: " << fixed << setprecision(1) << roundTime / 1000.0 << " s,"; + m_outputStream << " total: " << fixed << setprecision(1) << totalTime / 1000.0 << " s]"; m_outputStream << " ----------" << endl; } else if (m_population.individuals().size() > 0) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index abef48869064..7c69463916fb 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -71,7 +71,9 @@ class AlgorithmRunner private: void printRoundSummary( - size_t _round + size_t _round, + std::chrono::steady_clock::time_point _roundTimeStart, + std::chrono::steady_clock::time_point _totalTimeStart ) const; void printInitialPopulation() const; void populationAutosave() const; From 1272a9335cf0b746d0c93e90071bdd7d572944c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 29 Feb 2020 00:56:47 +0100 Subject: [PATCH 114/165] [yul-phaser] Add --mode option --- tools/yulPhaser/Phaser.cpp | 35 ++++++++++++++++++++++++++++++----- tools/yulPhaser/Phaser.h | 14 +++++++++++++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 344b932082cb..2a4ee4b86152 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -46,6 +46,12 @@ namespace po = boost::program_options; namespace { +map const PhaserModeToStringMap = +{ + {PhaserMode::RunAlgorithm, "run-algorithm"}, +}; +map const StringToPhaserModeMap = invertMap(PhaserModeToStringMap); + map const AlgorithmToStringMap = { {Algorithm::Random, "random"}, @@ -71,6 +77,8 @@ map const StringToMetricAggregatorChoiceMap = in } +istream& phaser::operator>>(istream& _inputStream, PhaserMode& _phaserMode) { return deserializeChoice(_inputStream, _phaserMode, StringToPhaserModeMap); } +ostream& phaser::operator<<(ostream& _outputStream, PhaserMode _phaserMode) { return serializeChoice(_outputStream, _phaserMode, PhaserModeToStringMap); } istream& phaser::operator>>(istream& _inputStream, Algorithm& _algorithm) { return deserializeChoice(_inputStream, _algorithm, StringToAlgorithmMap); } ostream& phaser::operator<<(ostream& _outputStream, Algorithm _algorithm) { return serializeChoice(_outputStream, _algorithm, AlgorithmToStringMap); } istream& phaser::operator>>(istream& _inputStream, MetricChoice& _metric) { return deserializeChoice(_inputStream, _metric, StringToMetricChoiceMap); } @@ -348,7 +356,7 @@ void Phaser::main(int _argc, char** _argv) initialiseRNG(arguments.value()); - runAlgorithm(arguments.value()); + runPhaser(arguments.value()); } Phaser::CommandLineDescription Phaser::buildCommandLineDescription() @@ -392,6 +400,12 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::value()->value_name(""), "The number of rounds after which the algorithm should stop. (default=no limit)." ) + ( + "mode", + po::value()->value_name("")->default_value(PhaserMode::RunAlgorithm), + "Mode of operation. The default is to run the algorithm but you can also tell phaser " + "to do something else with its parameters, e.g. just print the optimised programs and exit." + ) ; keywordDescription.add(generalDescription); @@ -618,13 +632,12 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c }; } -void Phaser::runAlgorithm(po::variables_map const& _arguments) +void Phaser::runPhaser(po::variables_map const& _arguments) { auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); auto cacheOptions = ProgramCacheFactory::Options::fromCommandLine(_arguments); auto metricOptions = FitnessMetricFactory::Options::fromCommandLine(_arguments); auto populationOptions = PopulationFactory::Options::fromCommandLine(_arguments); - auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); vector programs = ProgramFactory::build(programOptions); vector> programCaches = ProgramCacheFactory::build(cacheOptions, programs); @@ -632,11 +645,23 @@ void Phaser::runAlgorithm(po::variables_map const& _arguments) unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs), programCaches); Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); + if (_arguments["mode"].as() == PhaserMode::RunAlgorithm) + runAlgorithm(_arguments, move(population), move(programCaches)); +} + +void Phaser::runAlgorithm( + po::variables_map const& _arguments, + Population _population, + vector> _programCaches +) +{ + auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); + unique_ptr geneticAlgorithm = GeneticAlgorithmFactory::build( algorithmOptions, - population.individuals().size() + _population.individuals().size() ); - AlgorithmRunner algorithmRunner(population, move(programCaches), buildAlgorithmRunnerOptions(_arguments), cout); + AlgorithmRunner algorithmRunner(move(_population), move(_programCaches), buildAlgorithmRunnerOptions(_arguments), cout); algorithmRunner.run(*geneticAlgorithm); } diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index ba816044c46a..ef7c00f41749 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -47,6 +47,11 @@ class Population; class Program; class ProgramCache; +enum class PhaserMode +{ + RunAlgorithm, +}; + enum class Algorithm { Random, @@ -67,6 +72,8 @@ enum class MetricAggregatorChoice Minimum, }; +std::istream& operator>>(std::istream& _inputStream, solidity::phaser::PhaserMode& _phaserMode); +std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::PhaserMode _phaserMode); std::istream& operator>>(std::istream& _inputStream, solidity::phaser::Algorithm& _algorithm); std::ostream& operator<<(std::ostream& _outputStream, solidity::phaser::Algorithm _algorithm); std::istream& operator>>(std::istream& _inputStream, solidity::phaser::MetricChoice& _metric); @@ -223,7 +230,12 @@ class Phaser static void initialiseRNG(boost::program_options::variables_map const& _arguments); static AlgorithmRunner::Options buildAlgorithmRunnerOptions(boost::program_options::variables_map const& _arguments); - static void runAlgorithm(boost::program_options::variables_map const& _arguments); + static void runPhaser(boost::program_options::variables_map const& _arguments); + static void runAlgorithm( + boost::program_options::variables_map const& _arguments, + Population _population, + std::vector> _programCaches + ); }; } From d33ba54a38ebefe8861d947a620188fcb4fc9db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 29 Feb 2020 00:57:24 +0100 Subject: [PATCH 115/165] [yul-phaser] Add print-optimised-programs and print-optimised-asts modes --- tools/yulPhaser/Phaser.cpp | 41 +++++++++++++++++++++++++++++++++++++- tools/yulPhaser/Phaser.h | 8 ++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 2a4ee4b86152..0bfd6a4339ee 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -49,6 +49,8 @@ namespace map const PhaserModeToStringMap = { {PhaserMode::RunAlgorithm, "run-algorithm"}, + {PhaserMode::PrintOptimisedPrograms, "print-optimised-programs"}, + {PhaserMode::PrintOptimisedASTs, "print-optimised-asts"}, }; map const StringToPhaserModeMap = invertMap(PhaserModeToStringMap); @@ -642,11 +644,13 @@ void Phaser::runPhaser(po::variables_map const& _arguments) vector programs = ProgramFactory::build(programOptions); vector> programCaches = ProgramCacheFactory::build(cacheOptions, programs); - unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, move(programs), programCaches); + unique_ptr fitnessMetric = FitnessMetricFactory::build(metricOptions, programs, programCaches); Population population = PopulationFactory::build(populationOptions, move(fitnessMetric)); if (_arguments["mode"].as() == PhaserMode::RunAlgorithm) runAlgorithm(_arguments, move(population), move(programCaches)); + else + printOptimisedProgramsOrASTs(_arguments, population, move(programs), _arguments["mode"].as()); } void Phaser::runAlgorithm( @@ -665,3 +669,38 @@ void Phaser::runAlgorithm( AlgorithmRunner algorithmRunner(move(_population), move(_programCaches), buildAlgorithmRunnerOptions(_arguments), cout); algorithmRunner.run(*geneticAlgorithm); } + +void Phaser::printOptimisedProgramsOrASTs( + po::variables_map const& _arguments, + Population const& _population, + vector _programs, + PhaserMode phaserMode +) +{ + assert(phaserMode == PhaserMode::PrintOptimisedPrograms || phaserMode == PhaserMode::PrintOptimisedASTs); + assert(_programs.size() == _arguments["input-files"].as>().size()); + + if (_population.individuals().size() == 0) + { + cout << "" << endl; + return; + } + + vector const& paths = _arguments["input-files"].as>(); + for (auto& individual: _population.individuals()) + { + cout << "Chromosome: " << individual.chromosome << endl; + + for (size_t i = 0; i < _programs.size(); ++i) + { + for (size_t j = 0; j < _arguments["chromosome-repetitions"].as(); ++j) + _programs[i].optimise(individual.chromosome.optimisationSteps()); + + cout << "Program: " << paths[i] << endl; + if (phaserMode == PhaserMode::PrintOptimisedPrograms) + cout << _programs[i] << endl; + else + cout << _programs[i].toJson() << endl; + } + } +} diff --git a/tools/yulPhaser/Phaser.h b/tools/yulPhaser/Phaser.h index ef7c00f41749..77e9e48c8eae 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -50,6 +50,8 @@ class ProgramCache; enum class PhaserMode { RunAlgorithm, + PrintOptimisedPrograms, + PrintOptimisedASTs, }; enum class Algorithm @@ -236,6 +238,12 @@ class Phaser Population _population, std::vector> _programCaches ); + static void printOptimisedProgramsOrASTs( + boost::program_options::variables_map const& _arguments, + Population const& _population, + std::vector _programs, + PhaserMode phaserMode + ); }; } From 3e35decf2bade5d52018cfea98f611ad28a649b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 29 Feb 2020 01:53:11 +0100 Subject: [PATCH 116/165] [yul-phaser] ProgramCache: Add ability to gather cache stats --- test/yulPhaser/ProgramCache.cpp | 48 +++++++++++++++++++++++++++ tools/yulPhaser/ProgramCache.cpp | 57 ++++++++++++++++++++++++++++++++ tools/yulPhaser/ProgramCache.h | 26 +++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/test/yulPhaser/ProgramCache.cpp b/test/yulPhaser/ProgramCache.cpp index 598e7a16fba9..1ed6024bcafa 100644 --- a/test/yulPhaser/ProgramCache.cpp +++ b/test/yulPhaser/ProgramCache.cpp @@ -71,6 +71,15 @@ class ProgramCacheFixture BOOST_AUTO_TEST_SUITE(Phaser) BOOST_AUTO_TEST_SUITE(ProgramCacheTest) +BOOST_AUTO_TEST_CASE(CacheStats_operator_plus_should_add_stats_together) +{ + CacheStats statsA{11, 12, 13, {{1, 14}, {2, 15}}}; + CacheStats statsB{21, 22, 23, {{2, 24}, {3, 25}}}; + CacheStats statsC{32, 34, 36, {{1, 14}, {2, 39}, {3, 25}}}; + + BOOST_CHECK(statsA + statsB == statsC); +} + BOOST_FIXTURE_TEST_CASE(optimiseProgram_should_apply_optimisation_steps_to_program, ProgramCacheFixture) { Program expectedProgram = optimisedProgram(m_program, "IuO"); @@ -201,6 +210,45 @@ BOOST_FIXTURE_TEST_CASE(startRound_should_remove_entries_older_than_two_rounds, BOOST_TEST(m_programCache.size() == 0); } +BOOST_FIXTURE_TEST_CASE(gatherStats_should_return_cache_statistics, ProgramCacheFixture) +{ + size_t sizeI = optimisedProgram(m_program, "I").codeSize(); + size_t sizeIu = optimisedProgram(m_program, "Iu").codeSize(); + size_t sizeIuO = optimisedProgram(m_program, "IuO").codeSize(); + size_t sizeL = optimisedProgram(m_program, "L").codeSize(); + size_t sizeLT = optimisedProgram(m_program, "LT").codeSize(); + + m_programCache.optimiseProgram("L"); + m_programCache.optimiseProgram("Iu"); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"L", "I", "Iu"})); + CacheStats expectedStats1{0, 3, sizeL + sizeI + sizeIu, {{0, 3}}}; + BOOST_CHECK(m_programCache.gatherStats() == expectedStats1); + + m_programCache.optimiseProgram("IuO"); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"L", "I", "Iu", "IuO"})); + CacheStats expectedStats2{2, 4, sizeL + sizeI + sizeIu + sizeIuO, {{0, 4}}}; + BOOST_CHECK(m_programCache.gatherStats() == expectedStats2); + + m_programCache.startRound(1); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"L", "I", "Iu", "IuO"})); + BOOST_CHECK(m_programCache.gatherStats() == expectedStats2); + + m_programCache.optimiseProgram("IuO"); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"L", "I", "Iu", "IuO"})); + CacheStats expectedStats3{5, 4, sizeL + sizeI + sizeIu + sizeIuO, {{0, 1}, {1, 3}}}; + BOOST_CHECK(m_programCache.gatherStats() == expectedStats3); + + m_programCache.startRound(2); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"I", "Iu", "IuO"})); + CacheStats expectedStats4{5, 4, sizeI + sizeIu + sizeIuO, {{1, 3}}}; + BOOST_CHECK(m_programCache.gatherStats() == expectedStats4); + + m_programCache.optimiseProgram("LT"); + BOOST_REQUIRE((cachedKeys(m_programCache) == set{"L", "LT", "I", "Iu", "IuO"})); + CacheStats expectedStats5{5, 6, sizeL + sizeLT + sizeI + sizeIu + sizeIuO, {{1, 3}, {2, 2}}}; + BOOST_CHECK(m_programCache.gatherStats() == expectedStats5); +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END() diff --git a/tools/yulPhaser/ProgramCache.cpp b/tools/yulPhaser/ProgramCache.cpp index bd3b05114c96..7acec16bdfea 100644 --- a/tools/yulPhaser/ProgramCache.cpp +++ b/tools/yulPhaser/ProgramCache.cpp @@ -23,6 +23,30 @@ using namespace std; using namespace solidity::yul; using namespace solidity::phaser; +CacheStats& CacheStats::operator+=(CacheStats const& _other) +{ + hits += _other.hits; + misses += _other.misses; + totalCodeSize += _other.totalCodeSize; + + for (auto& [round, count]: _other.roundEntryCounts) + if (roundEntryCounts.find(round) != roundEntryCounts.end()) + roundEntryCounts.at(round) += count; + else + roundEntryCounts.insert({round, count}); + + return *this; +} + +bool CacheStats::operator==(CacheStats const& _other) const +{ + return + hits == _other.hits && + misses == _other.misses && + totalCodeSize == _other.totalCodeSize && + roundEntryCounts == _other.roundEntryCounts; +} + Program ProgramCache::optimiseProgram( string const& _abbreviatedOptimisationSteps, size_t _repetitionCount @@ -40,6 +64,7 @@ Program ProgramCache::optimiseProgram( { pair->second.roundNumber = m_currentRound; ++prefixSize; + ++m_hits; } else break; @@ -57,6 +82,7 @@ Program ProgramCache::optimiseProgram( intermediateProgram.optimise({stepName}); m_entries.insert({targetOptimisations.substr(0, i), {intermediateProgram, m_currentRound}}); + ++m_misses; } return intermediateProgram; @@ -92,3 +118,34 @@ Program const* ProgramCache::find(string const& _abbreviatedOptimisationSteps) c return &(pair->second.program); } + +CacheStats ProgramCache::gatherStats() const +{ + return { + /* hits = */ m_hits, + /* misses = */ m_misses, + /* totalCodeSize = */ calculateTotalCachedCodeSize(), + /* roundEntryCounts = */ countRoundEntries(), + }; +} + +size_t ProgramCache::calculateTotalCachedCodeSize() const +{ + size_t size = 0; + for (auto const& pair: m_entries) + size += pair.second.program.codeSize(); + + return size; +} + +map ProgramCache::countRoundEntries() const +{ + map counts; + for (auto& pair: m_entries) + if (counts.find(pair.second.roundNumber) != counts.end()) + ++counts.at(pair.second.roundNumber); + else + counts.insert({pair.second.roundNumber, 1}); + + return counts; +} diff --git a/tools/yulPhaser/ProgramCache.h b/tools/yulPhaser/ProgramCache.h index 433ba99c5ec9..8cc83009866e 100644 --- a/tools/yulPhaser/ProgramCache.h +++ b/tools/yulPhaser/ProgramCache.h @@ -39,6 +39,23 @@ struct CacheEntry roundNumber(_roundNumber) {} }; +/** + * Stores statistics about current cache usage. + */ +struct CacheStats +{ + size_t hits; + size_t misses; + size_t totalCodeSize; + std::map roundEntryCounts; + + CacheStats& operator+=(CacheStats const& _other); + CacheStats operator+(CacheStats const& _other) const { return CacheStats(*this) += _other; } + + bool operator==(CacheStats const& _other) const; + bool operator!=(CacheStats const& _other) const { return !(*this == _other); } +}; + /** * Class that optimises programs one step at a time which allows it to store and later reuse the * results of the intermediate steps. @@ -49,6 +66,8 @@ struct CacheEntry * encountered in the current and the previous rounds. Entries older than that get removed to * conserve memory. * + * @a gatherStats() allows getting statistics useful for determining cache effectiveness. + * * The current strategy does speed things up (about 4:1 hit:miss ratio observed in my limited * experiments) but there's room for improvement. We could fit more useful programs in * the cache by being more picky about which ones we choose. @@ -74,11 +93,16 @@ class ProgramCache Program const* find(std::string const& _abbreviatedOptimisationSteps) const; bool contains(std::string const& _abbreviatedOptimisationSteps) const { return find(_abbreviatedOptimisationSteps) != nullptr; } + CacheStats gatherStats() const; + std::map const& entries() const { return m_entries; }; Program const& program() const { return m_program; } size_t currentRound() const { return m_currentRound; } private: + size_t calculateTotalCachedCodeSize() const; + std::map countRoundEntries() const; + // The best matching data structure here would be a trie of chromosome prefixes but since // the programs are orders of magnitude larger than the prefixes, it does not really matter. // A map should be good enough. @@ -86,6 +110,8 @@ class ProgramCache Program m_program; size_t m_currentRound = 0; + size_t m_hits = 0; + size_t m_misses = 0; }; } From cd16a6e1780f9298170b96209cdb3429f72d15f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 29 Feb 2020 02:14:51 +0100 Subject: [PATCH 117/165] [yul-phaser] Add --show-cache-stats option --- test/yulPhaser/AlgorithmRunner.cpp | 106 ++++++++++++++++++++++++++++ tools/yulPhaser/AlgorithmRunner.cpp | 34 +++++++++ tools/yulPhaser/AlgorithmRunner.h | 2 + tools/yulPhaser/Phaser.cpp | 6 ++ 4 files changed, 148 insertions(+) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 831cb360a41d..fa87579ddcd5 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -277,6 +278,111 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_whole_initial_population_even_if_only_t BOOST_TEST(m_output.peek() == EOF); } +BOOST_FIXTURE_TEST_CASE(run_should_print_cache_stats_if_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 4; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + vector sourceStreams = { + CharStream("{mstore(10, 20)}", ""), + CharStream("{mstore(10, 20)\nsstore(10, 20)}", ""), + }; + vector programs = { + get(Program::load(sourceStreams[0])), + get(Program::load(sourceStreams[1])), + }; + vector> caches = { + make_shared(programs[0]), + make_shared(programs[1]), + }; + shared_ptr fitnessMetric = make_shared(vector>{ + make_shared(nullopt, caches[0]), + make_shared(nullopt, caches[1]), + }); + Population population = Population::makeRandom(fitnessMetric, 2, 0, 5); + + AlgorithmRunner runner(population, caches, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(caches[0]->currentRound() == m_options.maxRounds.value()); + BOOST_TEST(caches[1]->currentRound() == m_options.maxRounds.value()); + + CacheStats stats = caches[0]->gatherStats() + caches[1]->gatherStats(); + + for (size_t i = 0; i < m_options.maxRounds.value() - 1; ++i) + { + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + if (i > 0) + BOOST_TEST(nextLineMatches(m_output, regex(R"(Round\d+:\d+entries)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Round\d+:\d+entries)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalhits:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalmisses:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Sizeofcachedcode:\d+)"))); + } + + BOOST_REQUIRE(stats.roundEntryCounts.size() == 2); + BOOST_REQUIRE(stats.roundEntryCounts.count(m_options.maxRounds.value() - 1) == 1); + BOOST_REQUIRE(stats.roundEntryCounts.count(m_options.maxRounds.value()) == 1); + + size_t round = m_options.maxRounds.value(); + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex("Round" + toString(round - 1) + ":" + toString(stats.roundEntryCounts[round - 1]) + "entries"))); + BOOST_TEST(nextLineMatches(m_output, regex("Round" + toString(round) + ":" + toString(stats.roundEntryCounts[round]) + "entries"))); + BOOST_TEST(nextLineMatches(m_output, regex("Totalhits:" + toString(stats.hits)))); + BOOST_TEST(nextLineMatches(m_output, regex("Totalmisses:" + toString(stats.misses)))); + BOOST_TEST(nextLineMatches(m_output, regex("Sizeofcachedcode:" + toString(stats.totalCodeSize)))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_message_if_cache_stats_requested_but_cache_disabled, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + AlgorithmRunner runner(m_population, {nullptr}, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex(stripWhitespace("Program cache disabled")))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_partial_stats_and_message_if_some_caches_disabled, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + CharStream sourceStream = CharStream("{}", ""); + shared_ptr cache = make_shared(get(Program::load(sourceStream))); + + AlgorithmRunner runner(m_population, {cache, nullptr}, m_options, m_output); + BOOST_REQUIRE(cache->gatherStats().roundEntryCounts.size() == 0); + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalhits:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalmisses:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Sizeofcachedcode:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(stripWhitespace("Program cache disabled for 1 out of 2 programs")))); + BOOST_TEST(m_output.peek() == EOF); +} + BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) { m_options.maxRounds = 0; diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 9ddce41bce53..5e03e2820bd6 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -44,6 +44,7 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) randomiseDuplicates(); printRoundSummary(round, roundTimeStart, totalTimeStart); + printCacheStats(); populationAutosave(); } } @@ -90,6 +91,39 @@ void AlgorithmRunner::printInitialPopulation() const m_outputStream << m_population; } +void AlgorithmRunner::printCacheStats() const +{ + if (!m_options.showCacheStats) + return; + + CacheStats totalStats{}; + size_t disabledCacheCount = 0; + for (size_t i = 0; i < m_programCaches.size(); ++i) + if (m_programCaches[i] != nullptr) + totalStats += m_programCaches[i]->gatherStats(); + else + ++disabledCacheCount; + + m_outputStream << "---------- CACHE STATS ----------" << endl; + + if (disabledCacheCount < m_programCaches.size()) + { + for (auto& [round, count]: totalStats.roundEntryCounts) + m_outputStream << "Round " << round << ": " << count << " entries" << endl; + m_outputStream << "Total hits: " << totalStats.hits << endl; + m_outputStream << "Total misses: " << totalStats.misses << endl; + m_outputStream << "Size of cached code: " << totalStats.totalCodeSize << endl; + } + + if (disabledCacheCount == m_programCaches.size()) + m_outputStream << "Program cache disabled" << endl; + else if (disabledCacheCount > 0) + { + m_outputStream << "Program cache disabled for " << disabledCacheCount << " out of "; + m_outputStream << m_programCaches.size() << " programs" << endl; + } +} + void AlgorithmRunner::populationAutosave() const { if (!m_options.populationAutosaveFile.has_value()) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 7c69463916fb..d1cffb30ab15 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -51,6 +51,7 @@ class AlgorithmRunner bool showInitialPopulation = false; bool showOnlyTopChromosome = false; bool showRoundInfo = true; + bool showCacheStats = false; }; AlgorithmRunner( @@ -76,6 +77,7 @@ class AlgorithmRunner std::chrono::steady_clock::time_point _totalTimeStart ) const; void printInitialPopulation() const; + void printCacheStats() const; void populationAutosave() const; void randomiseDuplicates(); void cacheClear(); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 0bfd6a4339ee..6e6ec7a3f3fb 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -576,6 +576,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::bool_switch(), "Hide information about the current round (round number and elapsed time)." ) + ( + "show-cache-stats", + po::bool_switch(), + "Print information about cache size and effectiveness after each round." + ) ; keywordDescription.add(outputDescription); @@ -631,6 +636,7 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c _arguments["show-initial-population"].as(), _arguments["show-only-top-chromosome"].as(), !_arguments["hide-round"].as(), + _arguments["show-cache-stats"].as(), }; } From 58e3fca3de9245d170800964b26e61e050188657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 9 Mar 2020 19:19:42 +0100 Subject: [PATCH 118/165] [yul-phaser] AlgorithmRunner: Measure CPU time rather than wall-clock time --- tools/yulPhaser/AlgorithmRunner.cpp | 18 +++++++++--------- tools/yulPhaser/AlgorithmRunner.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 5e03e2820bd6..d3bda6960505 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -34,10 +34,10 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) printInitialPopulation(); cacheClear(); - chrono::steady_clock::time_point totalTimeStart = std::chrono::steady_clock::now(); + clock_t totalTimeStart = clock(); for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round) { - chrono::steady_clock::time_point roundTimeStart = std::chrono::steady_clock::now(); + clock_t roundTimeStart = clock(); cacheStartRound(round + 1); m_population = _algorithm.runNextRound(m_population); @@ -51,21 +51,21 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) void AlgorithmRunner::printRoundSummary( size_t _round, - chrono::steady_clock::time_point _roundTimeStart, - chrono::steady_clock::time_point _totalTimeStart + clock_t _roundTimeStart, + clock_t _totalTimeStart ) const { if (!m_options.showOnlyTopChromosome) { if (m_options.showRoundInfo) { - chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - auto roundTime = chrono::duration_cast(now - _roundTimeStart).count(); - auto totalTime = chrono::duration_cast(now - _totalTimeStart).count(); + clock_t now = clock(); + double roundTime = static_cast(now - _roundTimeStart) / CLOCKS_PER_SEC; + double totalTime = static_cast(now - _totalTimeStart) / CLOCKS_PER_SEC; m_outputStream << "---------- ROUND " << _round + 1; - m_outputStream << " [round: " << fixed << setprecision(1) << roundTime / 1000.0 << " s,"; - m_outputStream << " total: " << fixed << setprecision(1) << totalTime / 1000.0 << " s]"; + m_outputStream << " [round: " << fixed << setprecision(1) << roundTime << " s,"; + m_outputStream << " total: " << fixed << setprecision(1) << totalTime << " s]"; m_outputStream << " ----------" << endl; } else if (m_population.individuals().size() > 0) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index d1cffb30ab15..4326ce227b5e 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -73,8 +73,8 @@ class AlgorithmRunner private: void printRoundSummary( size_t _round, - std::chrono::steady_clock::time_point _roundTimeStart, - std::chrono::steady_clock::time_point _totalTimeStart + clock_t _roundTimeStart, + clock_t _totalTimeStart ) const; void printInitialPopulation() const; void printCacheStats() const; From 10e8d3616c0d24428f97b6e4d1ce62f03b51d642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 9 Mar 2020 19:23:25 +0100 Subject: [PATCH 119/165] [yul-phaser] AlgorithmRunner: Print total time when showing only the top chromosome --- test/yulPhaser/AlgorithmRunner.cpp | 2 +- tools/yulPhaser/AlgorithmRunner.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index fa87579ddcd5..9d062d0ac9e7 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -84,7 +84,7 @@ class AlgorithmRunnerFixture string topChromosomePattern(size_t roundNumber, Individual const& individual) const { ostringstream output; - output << roundNumber << "\\|" << individualPattern(individual); + output << roundNumber << R"(\|[0-9.]+\|)" << individualPattern(individual); return output.str(); } diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index d3bda6960505..c402e5d844d3 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -55,14 +55,14 @@ void AlgorithmRunner::printRoundSummary( clock_t _totalTimeStart ) const { + clock_t now = clock(); + double roundTime = static_cast(now - _roundTimeStart) / CLOCKS_PER_SEC; + double totalTime = static_cast(now - _totalTimeStart) / CLOCKS_PER_SEC; + if (!m_options.showOnlyTopChromosome) { if (m_options.showRoundInfo) { - clock_t now = clock(); - double roundTime = static_cast(now - _roundTimeStart) / CLOCKS_PER_SEC; - double totalTime = static_cast(now - _totalTimeStart) / CLOCKS_PER_SEC; - m_outputStream << "---------- ROUND " << _round + 1; m_outputStream << " [round: " << fixed << setprecision(1) << roundTime << " s,"; m_outputStream << " total: " << fixed << setprecision(1) << totalTime << " s]"; @@ -76,7 +76,10 @@ void AlgorithmRunner::printRoundSummary( else if (m_population.individuals().size() > 0) { if (m_options.showRoundInfo) + { m_outputStream << setw(5) << _round + 1 << " | "; + m_outputStream << setw(5) << fixed << setprecision(1) << totalTime << " | "; + } m_outputStream << m_population.individuals()[0] << endl; } From 3f524ccfe5d1c0bb7c5f18e814d4fd3a196a8b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 9 Mar 2020 19:24:37 +0100 Subject: [PATCH 120/165] [yul-phaser] Population: Print individuals in a more compact way --- test/yulPhaser/AlgorithmRunner.cpp | 3 +-- tools/yulPhaser/Population.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 9d062d0ac9e7..8dd6e7564382 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -76,8 +76,7 @@ class AlgorithmRunnerFixture string individualPattern(Individual const& individual) const { ostringstream output; - output << "Fitness:" << individual.fitness << ","; - output << "optimisations:" << individual.chromosome; + output << individual.fitness << individual.chromosome; return output.str(); } diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index 87df4e59b4dd..169cbfe30b18 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -43,8 +43,7 @@ ostream& operator<<(ostream& _stream, Population const& _population); ostream& phaser::operator<<(ostream& _stream, Individual const& _individual) { - _stream << "Fitness: " << _individual.fitness; - _stream << ", optimisations: " << _individual.chromosome; + _stream << _individual.fitness << " " << _individual.chromosome; return _stream; } From e41ea6d25e6ff3269248e4110c99376ceacdc098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 9 Mar 2020 19:26:40 +0100 Subject: [PATCH 121/165] [yul-phaser] Add --show-seed option and don't print seed by default --- tools/yulPhaser/Phaser.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 6e6ec7a3f3fb..2e38edbf097f 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -581,6 +581,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::bool_switch(), "Print information about cache size and effectiveness after each round." ) + ( + "show-seed", + po::bool_switch(), + "Print the selected random seed." + ) ; keywordDescription.add(outputDescription); @@ -622,7 +627,8 @@ void Phaser::initialiseRNG(po::variables_map const& _arguments) seed = SimulationRNG::generateSeed(); SimulationRNG::reset(seed); - cout << "Random seed: " << seed << endl; + if (_arguments["show-seed"].as()) + cout << "Random seed: " << seed << endl; } AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map const& _arguments) From e16c0c4133d4dcd624c6c1962db69449cb3da568 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Wed, 25 Mar 2020 23:46:26 -0400 Subject: [PATCH 122/165] Convert operator+(Population, Population) into a hidden friend --- tools/yulPhaser/Population.cpp | 6 ++++++ tools/yulPhaser/Population.h | 7 ++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/yulPhaser/Population.cpp b/tools/yulPhaser/Population.cpp index 87df4e59b4dd..71b32da7037d 100644 --- a/tools/yulPhaser/Population.cpp +++ b/tools/yulPhaser/Population.cpp @@ -118,15 +118,21 @@ Population Population::crossover(PairSelection const& _selection, function _mutation) const; Population crossover(PairSelection const& _selection, std::function _crossover) const; - friend Population (::operator+)(Population _a, Population _b); + + friend Population operator+(Population _a, Population _b); std::shared_ptr fitnessMetric() { return m_fitnessMetric; } std::vector const& individuals() const { return m_individuals; } From 5b4ea1eb895d5edc9a24ee5c6f96d8580eceec08 Mon Sep 17 00:00:00 2001 From: Martin Lundfall Date: Tue, 24 Mar 2020 13:22:25 +0100 Subject: [PATCH 123/165] CommandLineInterface: add storage-layout option to --combined-json --- Changelog.md | 2 +- solc/CommandLineInterface.cpp | 27 ++++++++++++++++++++++++--- solc/CommandLineInterface.h | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 2472d946712a..031fe5a6779c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,7 @@ Language Features: Compiler Features: * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. - + * Commandline Interface: Enable output of storage layout with `--storage-layout`. Bugfixes: * Inline Assembly: Fix internal error when accessing incorrect constant variables. diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e91f6446cc87..90c2931c56ab 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -147,6 +148,7 @@ static string const g_strOptimizeYul = "optimize-yul"; static string const g_strOutputDir = "output-dir"; static string const g_strOverwrite = "overwrite"; static string const g_strRevertStrings = "revert-strings"; +static string const g_strStorageLayout = "storage-layout"; /// Possible arguments to for --revert-strings static set const g_revertStringsArgs @@ -207,6 +209,7 @@ static string const g_argOptimizeRuns = g_strOptimizeRuns; static string const g_argOutputDir = g_strOutputDir; static string const g_argSignatureHashes = g_strSignatureHashes; static string const g_argStandardJSON = g_strStandardJSON; +static string const g_argStorageLayout = g_strStorageLayout; static string const g_argStrictAssembly = g_strStrictAssembly; static string const g_argVersion = g_strVersion; static string const g_stdinFileName = g_stdinFileNameStr; @@ -231,7 +234,8 @@ static set const g_combinedJsonArgs g_strOpcodes, g_strSignatureHashes, g_strSrcMap, - g_strSrcMapRuntime + g_strSrcMapRuntime, + g_strStorageLayout }; /// Possible arguments to for --machine @@ -293,7 +297,8 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args) g_argNatspecUser, g_argNatspecDev, g_argOpcodes, - g_argSignatureHashes + g_argSignatureHashes, + g_argStorageLayout }) if (_args.count(arg)) return true; @@ -433,6 +438,18 @@ void CommandLineInterface::handleABI(string const& _contract) sout() << "Contract JSON ABI" << endl << data << endl; } +void CommandLineInterface::handleStorageLayout(string const& _contract) +{ + if (!m_args.count(g_argStorageLayout)) + return; + + string data = jsonCompactPrint(m_compiler->storageLayout(_contract)); + if (m_args.count(g_argOutputDir)) + createFile(m_compiler->filesystemFriendlyName(_contract) + "_storage.json", data); + else + sout() << "Contract Storage Layout:" << endl << data << endl; +} + void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contract) { std::string argName; @@ -833,7 +850,8 @@ Allowed options)", (g_argSignatureHashes.c_str(), "Function signature hashes of the contracts.") (g_argNatspecUser.c_str(), "Natspec user documentation of all contracts.") (g_argNatspecDev.c_str(), "Natspec developer documentation of all contracts.") - (g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain."); + (g_argMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.") + (g_argStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables."); desc.add(outputComponents); po::options_description allOptions = desc; @@ -1276,6 +1294,8 @@ void CommandLineInterface::handleCombinedJSON() contractData[g_strOpcodes] = evmasm::disassemble(m_compiler->object(contractName).bytecode); if (requests.count(g_strAsm) && m_compiler->compilationSuccessful()) contractData[g_strAsm] = m_compiler->assemblyJSON(contractName); + if (requests.count(g_strStorageLayout) && m_compiler->compilationSuccessful()) + contractData[g_strStorageLayout] = jsonCompactPrint(m_compiler->storageLayout(contractName)); if (requests.count(g_strSrcMap) && m_compiler->compilationSuccessful()) { auto map = m_compiler->sourceMapping(contractName); @@ -1653,6 +1673,7 @@ void CommandLineInterface::outputCompilationResults() handleSignatureHashes(contract); handleMetadata(contract); handleABI(contract); + handleStorageLayout(contract); handleNatspec(true, contract); handleNatspec(false, contract); } // end of contracts iteration diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 417501907b1d..f6972cf04823 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -74,6 +74,7 @@ class CommandLineInterface void handleNatspec(bool _natspecDev, std::string const& _contract); void handleGasEstimation(std::string const& _contract); void handleFormal(); + void handleStorageLayout(std::string const& _contract); /// Fills @a m_sourceCodes initially and @a m_redirects. bool readInputFilesAndConfigureRemappings(); From 6474a358623ec831c21904e4249739aef7d88d79 Mon Sep 17 00:00:00 2001 From: Martin Lundfall Date: Tue, 24 Mar 2020 17:19:00 +0100 Subject: [PATCH 124/165] CMakeLists: ensure OSX deployment target supports std::visit --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a674c99e4e4..dba182345002 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ eth_policy() # project name and version should be set after cmake_policy CMP0048 set(PROJECT_VERSION "0.6.5") +# OSX target needed in order to support std::visit +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) include(TestBigEndian) From 37fb53bebdb602a4e64c51a15ecf6fb624e0cea7 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 26 Feb 2020 15:01:05 +0100 Subject: [PATCH 125/165] Add a security policy and link it in README. Co-Authored-By: chriseth --- README.md | 5 +++++ SECURITY.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 SECURITY.md diff --git a/README.md b/README.md index c0a98aefa7c2..c3636ff064d6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Solidity is a statically typed, contract-oriented, high-level language for imple - [Development](#development) - [Maintainers](#maintainers) - [License](#license) +- [Security](#security) ## Background @@ -75,3 +76,7 @@ releases [in the projects section](https://github.com/ethereum/solidity/projects Solidity is licensed under [GNU General Public License v3.0](LICENSE.txt). Some third-party code has its [own licensing terms](cmake/templates/license.h.in). + +## Security + +The security policy may be [found here](SECURITY.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..dd39453e853b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,52 @@ +# Security Policy + +The Solidity team and community take all security bugs in Solidity seriously. +We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions. + +## Scope + +Bugs in the Solidity repository are in scope. +Bugs in third-party dependencies e.g., jsoncpp, boost etc. are not in scope unless they result in a Solidity specific bug. + +Only bugs that have a demonstrable security impact on smart contracts are in scope. +For example, a Solidity program whose optimization is incorrect (e.g., leads to an incorrect output) qualifies as a security bug. +Please note that the [rules][2] of the [Ethereum bounty program][1] have precedence over this security policy. + +## Supported Versions + +As a general rule, only the latest release gets security updates. +Exceptions may be made when the current breaking release is relatively new, e.g. less than three months old. +If you are reporting a bug, please state clearly the Solidity version(s) it affects. + +Example 1: Assuming the current release is `0.6.3` and a security bug has been found in it that affects both `0.5.x` and `0.6.x` trees, we may not only patch `0.6.3` (the bug-fix release numbered `0.6.4`) but `0.5.x` as well (the bug-fix release numbered `0.5.(x+1)`). + +Example 2: Assuming the current release is `0.6.25` and a security bug has been found in it, we may only patch `0.6.25` (in the bug-fix release numbered `0.6.26`) even if the bug affects a previous tree such as `0.5.x`. + +## Reporting a Vulnerability + +To report a vulnerability, please follow the instructions stated in the [Ethereum bounty program][1]. + +In the bug report, please include all details necessary to reproduce the vulnerability such as: + +- Input program that triggers the bug +- Compiler version affected +- Target EVM version +- Framework/IDE if applicable +- EVM execution environment/client if applicable +- Operating system + +Please include steps to reproduce the bug you have found in as much detail as possible. + +Once we have received your bug report, we will try to reproduce it and provide a more detailed response. +Once the reported bug has been successfully reproduced, the Solidity team will work on a fix. + +The Solidity team maintains the following JSON-formatted lists of patched security vulnerabilities: + +- [Summary of known security vulnerabilities][3] +- [List of security vulnerabilities affecting a specific version of the compiler][4]. + + +[1]: https://bounty.ethereum.org/ +[2]: https://bounty.ethereum.org/#rules +[3]: https://solidity.readthedocs.io/en/develop/bugs.html +[4]: https://github.com/ethereum/solidity/blob/develop/docs/bugs_by_version.json From d2f65ea8b11f3be7281347390d739b9fec3c61ce Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 24 Mar 2020 20:51:52 +0100 Subject: [PATCH 126/165] [SMTChecker] Add SortProvider --- libsolidity/CMakeLists.txt | 2 + libsolidity/formal/CHC.cpp | 35 +++---- libsolidity/formal/EncodingContext.cpp | 4 +- libsolidity/formal/SolverInterface.h | 90 +----------------- libsolidity/formal/Sorts.cpp | 29 ++++++ libsolidity/formal/Sorts.h | 125 +++++++++++++++++++++++++ libsolidity/formal/SymbolicTypes.cpp | 17 ++-- 7 files changed, 179 insertions(+), 123 deletions(-) create mode 100644 libsolidity/formal/Sorts.cpp create mode 100644 libsolidity/formal/Sorts.h diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index bb54c836f83d..ba2651e94e75 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -100,6 +100,8 @@ set(sources formal/SMTPortfolio.cpp formal/SMTPortfolio.h formal/SolverInterface.h + formal/Sorts.cpp + formal/Sorts.h formal/SSAVariable.cpp formal/SSAVariable.h formal/SymbolicTypes.cpp diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 1e851937c4a1..e10c16d39ec1 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -79,10 +79,9 @@ void CHC::analyze(SourceUnit const& _source) resetSourceAnalysis(); - auto boolSort = make_shared(smt::Kind::Bool); auto genesisSort = make_shared( vector(), - boolSort + smt::SortProvider::boolSort ); m_genesisPredicate = createSymbolicBlock(genesisSort, "genesis"); addRule(genesis(), "genesis"); @@ -131,12 +130,9 @@ bool CHC::visit(ContractDefinition const& _contract) clearIndices(&_contract); - - // TODO create static instances for Bool/Int sorts in SolverInterface. - auto boolSort = make_shared(smt::Kind::Bool); auto errorFunctionSort = make_shared( vector(), - boolSort + smt::SortProvider::boolSort ); string suffix = _contract.name() + "_" + to_string(_contract.id()); @@ -664,29 +660,25 @@ vector CHC::stateSorts(ContractDefinition const& _contract) smt::SortPointer CHC::constructorSort() { - auto boolSort = make_shared(smt::Kind::Bool); - auto intSort = make_shared(smt::Kind::Int); return make_shared( - vector{intSort} + m_stateSorts, - boolSort + vector{smt::SortProvider::intSort} + m_stateSorts, + smt::SortProvider::boolSort ); } smt::SortPointer CHC::interfaceSort() { - auto boolSort = make_shared(smt::Kind::Bool); return make_shared( m_stateSorts, - boolSort + smt::SortProvider::boolSort ); } smt::SortPointer CHC::interfaceSort(ContractDefinition const& _contract) { - auto boolSort = make_shared(smt::Kind::Bool); return make_shared( stateSorts(_contract), - boolSort + smt::SortProvider::boolSort ); } @@ -703,8 +695,6 @@ smt::SortPointer CHC::interfaceSort(ContractDefinition const& _contract) /// - 1 set of output variables smt::SortPointer CHC::sort(FunctionDefinition const& _function) { - auto boolSort = make_shared(smt::Kind::Bool); - auto intSort = make_shared(smt::Kind::Int); vector inputSorts; for (auto const& var: _function.parameters()) inputSorts.push_back(smt::smtSortAbstractFunction(*var->type())); @@ -712,8 +702,8 @@ smt::SortPointer CHC::sort(FunctionDefinition const& _function) for (auto const& var: _function.returnParameters()) outputSorts.push_back(smt::smtSortAbstractFunction(*var->type())); return make_shared( - vector{intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts, - boolSort + vector{smt::SortProvider::intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts, + smt::SortProvider::boolSort ); } @@ -725,13 +715,12 @@ smt::SortPointer CHC::sort(ASTNode const* _node) auto fSort = dynamic_pointer_cast(sort(*m_currentFunction)); solAssert(fSort, ""); - auto boolSort = make_shared(smt::Kind::Bool); vector varSorts; for (auto const& var: m_currentFunction->localVariables()) varSorts.push_back(smt::smtSortAbstractFunction(*var->type())); return make_shared( fSort->domain + varSorts, - boolSort + smt::SortProvider::boolSort ); } @@ -740,16 +729,14 @@ smt::SortPointer CHC::summarySort(FunctionDefinition const& _function, ContractD auto stateVariables = stateVariablesIncludingInheritedAndPrivate(_contract); auto sorts = stateSorts(_contract); - auto boolSort = make_shared(smt::Kind::Bool); - auto intSort = make_shared(smt::Kind::Int); vector inputSorts, outputSorts; for (auto const& var: _function.parameters()) inputSorts.push_back(smt::smtSortAbstractFunction(*var->type())); for (auto const& var: _function.returnParameters()) outputSorts.push_back(smt::smtSortAbstractFunction(*var->type())); return make_shared( - vector{intSort} + sorts + inputSorts + sorts + outputSorts, - boolSort + vector{smt::SortProvider::intSort} + sorts + inputSorts + sorts + outputSorts, + smt::SortProvider::boolSort ); } diff --git a/libsolidity/formal/EncodingContext.cpp b/libsolidity/formal/EncodingContext.cpp index ff193d2e2a4b..1f7b7a5e011c 100644 --- a/libsolidity/formal/EncodingContext.cpp +++ b/libsolidity/formal/EncodingContext.cpp @@ -28,8 +28,8 @@ EncodingContext::EncodingContext(): m_thisAddress(make_unique("this", *this)) { auto sort = make_shared( - make_shared(Kind::Int), - make_shared(Kind::Int) + SortProvider::intSort, + SortProvider::intSort ); m_balances = make_unique(sort, "balances", *this); } diff --git a/libsolidity/formal/SolverInterface.h b/libsolidity/formal/SolverInterface.h index 512be65bb2e0..106ada82092c 100644 --- a/libsolidity/formal/SolverInterface.h +++ b/libsolidity/formal/SolverInterface.h @@ -17,6 +17,8 @@ #pragma once +#include + #include #include #include @@ -52,94 +54,6 @@ enum class CheckResult SATISFIABLE, UNSATISFIABLE, UNKNOWN, CONFLICTING, ERROR }; -enum class Kind -{ - Int, - Bool, - Function, - Array, - Sort -}; - -struct Sort -{ - Sort(Kind _kind): - kind(_kind) {} - virtual ~Sort() = default; - virtual bool operator==(Sort const& _other) const { return kind == _other.kind; } - - Kind const kind; -}; -using SortPointer = std::shared_ptr; - -struct FunctionSort: public Sort -{ - FunctionSort(std::vector _domain, SortPointer _codomain): - Sort(Kind::Function), domain(std::move(_domain)), codomain(std::move(_codomain)) {} - bool operator==(Sort const& _other) const override - { - if (!Sort::operator==(_other)) - return false; - auto _otherFunction = dynamic_cast(&_other); - solAssert(_otherFunction, ""); - if (domain.size() != _otherFunction->domain.size()) - return false; - if (!std::equal( - domain.begin(), - domain.end(), - _otherFunction->domain.begin(), - [&](SortPointer _a, SortPointer _b) { return *_a == *_b; } - )) - return false; - solAssert(codomain, ""); - solAssert(_otherFunction->codomain, ""); - return *codomain == *_otherFunction->codomain; - } - - std::vector domain; - SortPointer codomain; -}; - -struct ArraySort: public Sort -{ - /// _domain is the sort of the indices - /// _range is the sort of the values - ArraySort(SortPointer _domain, SortPointer _range): - Sort(Kind::Array), domain(std::move(_domain)), range(std::move(_range)) {} - bool operator==(Sort const& _other) const override - { - if (!Sort::operator==(_other)) - return false; - auto _otherArray = dynamic_cast(&_other); - solAssert(_otherArray, ""); - solAssert(_otherArray->domain, ""); - solAssert(_otherArray->range, ""); - solAssert(domain, ""); - solAssert(range, ""); - return *domain == *_otherArray->domain && *range == *_otherArray->range; - } - - SortPointer domain; - SortPointer range; -}; - -struct SortSort: public Sort -{ - SortSort(SortPointer _inner): Sort(Kind::Sort), inner(std::move(_inner)) {} - bool operator==(Sort const& _other) const override - { - if (!Sort::operator==(_other)) - return false; - auto _otherSort = dynamic_cast(&_other); - solAssert(_otherSort, ""); - solAssert(_otherSort->inner, ""); - solAssert(inner, ""); - return *inner == *_otherSort->inner; - } - - SortPointer inner; -}; - // Forward declaration. SortPointer smtSort(Type const& _type); diff --git a/libsolidity/formal/Sorts.cpp b/libsolidity/formal/Sorts.cpp new file mode 100644 index 000000000000..195048e56ee8 --- /dev/null +++ b/libsolidity/formal/Sorts.cpp @@ -0,0 +1,29 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + + +#include + +using namespace std; + +namespace solidity::frontend::smt +{ + +shared_ptr const SortProvider::boolSort{make_shared(Kind::Bool)}; +shared_ptr const SortProvider::intSort{make_shared(Kind::Int)}; + +} diff --git a/libsolidity/formal/Sorts.h b/libsolidity/formal/Sorts.h new file mode 100644 index 000000000000..d266444625ea --- /dev/null +++ b/libsolidity/formal/Sorts.h @@ -0,0 +1,125 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace solidity::frontend::smt +{ + +enum class Kind +{ + Int, + Bool, + Function, + Array, + Sort +}; + +struct Sort +{ + Sort(Kind _kind): + kind(_kind) {} + virtual ~Sort() = default; + virtual bool operator==(Sort const& _other) const { return kind == _other.kind; } + + Kind const kind; +}; +using SortPointer = std::shared_ptr; + +struct FunctionSort: public Sort +{ + FunctionSort(std::vector _domain, SortPointer _codomain): + Sort(Kind::Function), domain(std::move(_domain)), codomain(std::move(_codomain)) {} + bool operator==(Sort const& _other) const override + { + if (!Sort::operator==(_other)) + return false; + auto _otherFunction = dynamic_cast(&_other); + solAssert(_otherFunction, ""); + if (domain.size() != _otherFunction->domain.size()) + return false; + if (!std::equal( + domain.begin(), + domain.end(), + _otherFunction->domain.begin(), + [&](SortPointer _a, SortPointer _b) { return *_a == *_b; } + )) + return false; + solAssert(codomain, ""); + solAssert(_otherFunction->codomain, ""); + return *codomain == *_otherFunction->codomain; + } + + std::vector domain; + SortPointer codomain; +}; + +struct ArraySort: public Sort +{ + /// _domain is the sort of the indices + /// _range is the sort of the values + ArraySort(SortPointer _domain, SortPointer _range): + Sort(Kind::Array), domain(std::move(_domain)), range(std::move(_range)) {} + bool operator==(Sort const& _other) const override + { + if (!Sort::operator==(_other)) + return false; + auto _otherArray = dynamic_cast(&_other); + solAssert(_otherArray, ""); + solAssert(_otherArray->domain, ""); + solAssert(_otherArray->range, ""); + solAssert(domain, ""); + solAssert(range, ""); + return *domain == *_otherArray->domain && *range == *_otherArray->range; + } + + SortPointer domain; + SortPointer range; +}; + +struct SortSort: public Sort +{ + SortSort(SortPointer _inner): Sort(Kind::Sort), inner(std::move(_inner)) {} + bool operator==(Sort const& _other) const override + { + if (!Sort::operator==(_other)) + return false; + auto _otherSort = dynamic_cast(&_other); + solAssert(_otherSort, ""); + solAssert(_otherSort->inner, ""); + solAssert(inner, ""); + return *inner == *_otherSort->inner; + } + + SortPointer inner; +}; + +/** Frequently used sorts.*/ +struct SortProvider +{ + static std::shared_ptr const boolSort; + static std::shared_ptr const intSort; +}; + +} diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index a2475b337f49..1d9655a9c909 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -32,9 +32,9 @@ SortPointer smtSort(frontend::Type const& _type) switch (smtKind(_type.category())) { case Kind::Int: - return make_shared(Kind::Int); + return SortProvider::intSort; case Kind::Bool: - return make_shared(Kind::Bool); + return SortProvider::boolSort; case Kind::Function: { auto fType = dynamic_cast(&_type); @@ -45,10 +45,10 @@ SortPointer smtSort(frontend::Type const& _type) // TODO change this when we support tuples. if (returnTypes.size() == 0) // We cannot declare functions without a return sort, so we use the smallest. - returnSort = make_shared(Kind::Bool); + returnSort = SortProvider::boolSort; else if (returnTypes.size() > 1) // Abstract sort. - returnSort = make_shared(Kind::Int); + returnSort = SortProvider::intSort; else returnSort = smtSort(*returnTypes.front()); return make_shared(parameterSorts, returnSort); @@ -65,20 +65,19 @@ SortPointer smtSort(frontend::Type const& _type) { auto stringLitType = dynamic_cast(&_type); solAssert(stringLitType, ""); - auto intSort = make_shared(Kind::Int); - return make_shared(intSort, intSort); + return make_shared(SortProvider::intSort, SortProvider::intSort); } else { solAssert(isArray(_type.category()), ""); auto arrayType = dynamic_cast(&_type); solAssert(arrayType, ""); - return make_shared(make_shared(Kind::Int), smtSortAbstractFunction(*arrayType->baseType())); + return make_shared(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType())); } } default: // Abstract case. - return make_shared(Kind::Int); + return SortProvider::intSort; } } @@ -93,7 +92,7 @@ vector smtSort(vector const& _types) SortPointer smtSortAbstractFunction(frontend::Type const& _type) { if (isFunction(_type.category())) - return make_shared(Kind::Int); + return SortProvider::intSort; return smtSort(_type); } From 67e9776418e155a663dd5076d41829249f5b64f2 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Fri, 20 Mar 2020 18:32:30 -0500 Subject: [PATCH 127/165] Extract 45 tests from SolidityEndToEndTest.cpp --- test/libsolidity/SolidityEndToEndTest.cpp | 1296 +---------------- .../extracted/abi_decode_calldata.sol | 11 + .../extracted/abi_decode_simple.sol | 7 + .../extracted/abi_decode_simple_storage.sol | 10 + .../extracted/abi_encode_empty_string.sol | 11 + .../arrays_complex_from_and_to_storage.sol | 18 + .../arrays_complex_memory_index_access.sol | 13 + ...signment_to_const_var_involving_keccak.sol | 9 + .../bitwise_shifting_constantinople.sol | 34 + ...twise_shifting_constantinople_combined.sol | 122 ++ ...wise_shifting_constants_constantinople.sol | 83 ++ .../extracted/bool_conversion.sol | 23 + .../extracted/bool_conversion_v2.sol | 24 + .../extracted/bytes_memory_index_access.sol | 13 + .../calldata_array_dynamic_bytes.sol | 74 + .../calldata_bytes_array_to_memory.sol | 18 + .../extracted/calldata_string_array.sol | 15 + .../extracted/calldata_struct_cleaning.sol | 22 + .../extracted/cleanup_address_types.sol | 17 + .../extracted/cleanup_address_types_v2.sol | 18 + .../extracted/cleanup_bytes_types.sol | 13 + .../extracted/cleanup_bytes_types_v2.sol | 14 + .../extracted/delegatecall_return_value.sol | 37 + ...elegatecall_return_value_pre_byzantium.sol | 39 + .../extracted/fixed_arrays_in_storage.sol | 45 + .../extracted/fixed_bytes_index_access.sol | 17 + .../extracted/function_types_sig.sol | 26 + .../iterated_keccak256_with_bytes.sol | 12 + .../keccak256_multiple_arguments.sol | 7 + ...ltiple_arguments_with_numeric_literals.sol | 7 + ...ultiple_arguments_with_string_literals.sol | 12 + ...mory_arrays_dynamic_index_access_write.sol | 19 + .../memory_arrays_index_access_write.sol | 14 + .../extracted/memory_structs_nested_load.sol | 69 + .../semanticTests/extracted/msg_sig.sol | 9 + .../msg_sig_after_internal_call_is_same.sol | 13 + .../extracted/multi_modifiers.sol | 23 + .../extracted/reusing_memory.sol | 26 + .../extracted/shift_right_garbled.sol | 14 + .../extracted/shift_right_garbled_signed.sol | 30 + .../shift_right_garbled_signed_v2.sol | 31 + .../extracted/shift_right_garbled_v2.sol | 15 + ...right_negative_lvalue_signextend_int16.sol | 13 + ...ht_negative_lvalue_signextend_int16_v2.sol | 14 + ...right_negative_lvalue_signextend_int32.sol | 13 + ...ht_negative_lvalue_signextend_int32_v2.sol | 14 + ..._right_negative_lvalue_signextend_int8.sol | 13 + ...ght_negative_lvalue_signextend_int8_v2.sol | 14 + .../staticcall_for_view_and_pure.sol | 39 + ...iccall_for_view_and_pure_pre_byzantium.sol | 39 + .../extracted/string_allocation_bug.sol | 20 + .../extracted/string_bytes_conversion.sol | 17 + .../extracted/strings_in_struct.sol | 35 + .../extracted/struct_constructor_nested.sol | 30 + 54 files changed, 1309 insertions(+), 1282 deletions(-) create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_simple.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol create mode 100644 test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol create mode 100644 test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol create mode 100644 test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol create mode 100644 test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol create mode 100644 test/libsolidity/semanticTests/extracted/bool_conversion.sol create mode 100644 test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_string_array.sol create mode 100644 test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_address_types.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol create mode 100644 test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol create mode 100644 test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol create mode 100644 test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol create mode 100644 test/libsolidity/semanticTests/extracted/function_types_sig.sol create mode 100644 test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol create mode 100644 test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol create mode 100644 test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol create mode 100644 test/libsolidity/semanticTests/extracted/msg_sig.sol create mode 100644 test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol create mode 100644 test/libsolidity/semanticTests/extracted/multi_modifiers.sol create mode 100644 test/libsolidity/semanticTests/extracted/reusing_memory.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_garbled.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol create mode 100644 test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol create mode 100644 test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol create mode 100644 test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol create mode 100644 test/libsolidity/semanticTests/extracted/string_allocation_bug.sol create mode 100644 test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol create mode 100644 test/libsolidity/semanticTests/extracted/strings_in_struct.sol create mode 100644 test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index ae39bec0ecb4..69e645494cec 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1024,39 +1024,6 @@ BOOST_AUTO_TEST_CASE(blockchain) ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7)); } -BOOST_AUTO_TEST_CASE(msg_sig) -{ - char const* sourceCode = R"( - contract test { - function foo(uint256 a) public returns (bytes4 value) { - return msg.sig; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo(uint256)", 0), encodeArgs(asString(FixedHash<4>(util::keccak256("foo(uint256)")).asBytes()))); - ) -} - -BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same) -{ - char const* sourceCode = R"( - contract test { - function boo() public returns (bytes4 value) { - return msg.sig; - } - function foo(uint256 a) public returns (bytes4 value) { - return boo(); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo(uint256)", 0), encodeArgs(asString(FixedHash<4>(util::keccak256("foo(uint256)")).asBytes()))); - ) -} - BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = R"( @@ -2403,96 +2370,6 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) ) } -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) -{ - char const* sourceCode = R"( - contract c { - function foo(uint a, uint b, uint c) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, c)); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - toBigEndian(u256(12)) + - toBigEndian(u256(13)) - ) - )); -} - -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_numeric_literals) -{ - char const* sourceCode = R"( - contract c { - function foo(uint a, uint16 b) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, uint8(145))); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - bytes{0x0, 0xc} + - bytes(1, 0x91) - ) - )); -} - -BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals) -{ - char const* sourceCode = R"( - contract c { - function foo() public returns (bytes32 d) - { - d = keccak256("foo"); - } - function bar(uint a, uint16 b) public returns (bytes32 d) - { - d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); - } - } - )"; - compileAndRun(sourceCode); - - ABI_CHECK(callContractFunction("foo()"), encodeArgs(util::keccak256("foo"))); - - ABI_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12), encodeArgs( - util::keccak256( - toBigEndian(u256(10)) + - bytes{0x0, 0xc} + - bytes(1, 0x91) + - bytes{0x66, 0x6f, 0x6f} - ) - )); -} - -BOOST_AUTO_TEST_CASE(iterated_keccak256_with_bytes) -{ - char const* sourceCode = R"ABC( - contract c { - bytes data; - function foo() public returns (bytes32) - { - data.push("x"); - data.push("y"); - data.push("z"); - return keccak256(abi.encodePacked("b", keccak256(data), "a")); - } - } - )ABC"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("foo()"), encodeArgs( - u256(util::keccak256(bytes{'b'} + util::keccak256("xyz").asBytes() + bytes{'a'})) - )); -} - BOOST_AUTO_TEST_CASE(generic_call) { char const* sourceCode = R"**( @@ -3095,33 +2972,6 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) ); } -BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) -{ - char const* sourceCode = R"( - contract c { - struct Data { uint x; uint y; } - Data[2**10] data; - uint[2**10 + 3] ids; - function setIDStatic(uint id) public { ids[2] = id; } - function setID(uint index, uint id) public { ids[index] = id; } - function setData(uint index, uint x, uint y) public { data[index].x = x; data[index].y = y; } - function getID(uint index) public returns (uint) { return ids[index]; } - function getData(uint index) public returns (uint x, uint y) { x = data[index].x; y = data[index].y; } - function getLengths() public returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("setIDStatic(uint256)", 11), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 2), encodeArgs(11)); - ABI_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8), bytes()); - ABI_CHECK(callContractFunction("getID(uint256)", 7), encodeArgs(8)); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9), bytes()); - ABI_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11), bytes()); - ABI_CHECK(callContractFunction("getData(uint256)", 7), encodeArgs(8, 9)); - ABI_CHECK(callContractFunction("getData(uint256)", 8), encodeArgs(10, 11)); - ABI_CHECK(callContractFunction("getLengths()"), encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); -} - BOOST_AUTO_TEST_CASE(fixed_array_cleanup) { char const* sourceCode = R"( @@ -3662,19 +3512,6 @@ BOOST_AUTO_TEST_CASE(array_copy_including_mapping) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) -{ - char const* sourceCode = R"( - contract C { - bytes32 constant x = keccak256("abc"); - function f() public returns (bytes32) { return x; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(util::keccak256("abc"))); -} - -// Disabled until https://github.com/ethereum/solidity/issues/715 is implemented //BOOST_AUTO_TEST_CASE(assignment_to_const_array_vars) //{ // char const* sourceCode = R"( @@ -3733,35 +3570,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) BOOST_CHECK(storageEmpty(m_contractAddress)); } -BOOST_AUTO_TEST_CASE(bool_conversion) -{ - char const* sourceCode = R"( - contract C { - function f(bool _b) public returns(uint) { - if (_b) - return 1; - else - return 0; - } - function g(bool _in) public returns (bool _out) { - _out = _in; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(bool)", 0), encodeArgs(0)); - ABI_CHECK(callContractFunction("f(bool)", 1), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 0), encodeArgs(0)); - ABI_CHECK(callContractFunction("g(bool)", 1), encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 2), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 3), v2 ? encodeArgs() : encodeArgs(1)); - ABI_CHECK(callContractFunction("g(bool)", 255), v2 ? encodeArgs() : encodeArgs(1)); -} - BOOST_AUTO_TEST_CASE(invalid_enum_logged) { char const* sourceCode = R"( @@ -3837,32 +3645,6 @@ BOOST_AUTO_TEST_CASE(failing_send) BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); } -BOOST_AUTO_TEST_CASE(reusing_memory) -{ - // Invoke some features that use memory and test that they do not interfere with each other. - char const* sourceCode = R"( - contract Helper { - uint public flag; - constructor(uint x) public { - flag = x; - } - } - contract Main { - mapping(uint => uint) map; - function f(uint x) public returns (uint) { - map[x] = x; - return (new Helper(uint(keccak256(abi.encodePacked(this.g(map[x])))))).flag(); - } - function g(uint a) public returns (uint) - { - return map[a]; - } - } - )"; - compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(util::keccak256(util::toBigEndian(u256(0x34))))); -} - BOOST_AUTO_TEST_CASE(return_string) { char const* sourceCode = R"( @@ -4195,83 +3977,6 @@ BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size()), data)); } -BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) -{ - char const* sourceCode = R"( - contract Test { - uint24[3][] public data; - function set(uint24[3][] memory _data) public returns (uint) { - data = _data; - return data.length; - } - function get() public returns (uint24[3][] memory) { - return data; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; - BOOST_REQUIRE( - callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == - encodeArgs(u256(data.size() / 3)) - ); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)), encodeArgs(u256(9))); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)), encodeArgs(u256(17))); - ABI_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0x20), u256(data.size() / 3), data)); -} - -BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) -{ - char const* sourceCode = R"( - contract Test { - function set(uint24[3][] memory _data, uint a, uint b) public returns (uint l, uint e) { - l = _data.length; - e = _data[a][b]; - } - } - )"; - vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Test"); - - BOOST_REQUIRE(callContractFunction( - "set(uint24[3][],uint256,uint256)", - u256(0x60), - u256(3), - u256(2), - u256(data.size() / 3), - data - ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); - ); -} - -BOOST_AUTO_TEST_CASE(bytes_memory_index_access) -{ - char const* sourceCode = R"( - contract Test { - function set(bytes memory _data, uint i) public returns (uint l, byte c) { - l = _data.length; - c = _data[i]; - } - } - )"; - string data("abcdefgh"); - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Test"); - - BOOST_REQUIRE(callContractFunction( - "set(bytes,uint256)", - u256(0x40), - u256(3), - u256(data.size()), - data - ) == encodeArgs(u256(data.size()), string("d"))); - ); -} - BOOST_AUTO_TEST_CASE(memory_types_initialisation) { char const* sourceCode = R"( @@ -4323,128 +4028,6 @@ BOOST_AUTO_TEST_CASE(memory_arrays_delete) ABI_CHECK(callContractFunction("del()"), encodeArgs(data)); } -BOOST_AUTO_TEST_CASE(memory_arrays_index_access_write) -{ - char const* sourceCode = R"( - contract Test { - function set(uint24[3][4] memory x) public { - x[2][2] = 1; - x[3][2] = 7; - } - function f() public returns (uint24[3][4] memory){ - uint24[3][4] memory data; - set(data); - return data; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data(3 * 4); - data[3 * 2 + 2] = 1; - data[3 * 3 + 2] = 7; - ABI_CHECK(callContractFunction("f()"), encodeArgs(data)); -} - -BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) -{ - char const* sourceCode = R"( - contract Test { - uint24[3][][4] data; - function set(uint24[3][][4] memory x) internal returns (uint24[3][][4] memory) { - x[1][2][2] = 1; - x[1][3][2] = 7; - return x; - } - function f() public returns (uint24[3][] memory) { - while (data[1].length < 4) - data[1].push(); - return set(data)[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - vector data(3 * 4); - data[3 * 2 + 2] = 1; - data[3 * 3 + 2] = 7; - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x20), u256(4), data)); -} - -BOOST_AUTO_TEST_CASE(memory_structs_nested_load) -{ - char const* sourceCode = R"( - contract Test { - struct S { uint8 x; uint16 y; uint z; } - struct X { uint8 x; S s; uint8[2] a; } - X m_x; - function load() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { - m_x.x = 1; - m_x.s.x = 2; - m_x.s.y = 3; - m_x.s.z = 4; - m_x.a[0] = 5; - m_x.a[1] = 6; - X memory d = m_x; - a = d.x; - x = d.s.x; - y = d.s.y; - z = d.s.z; - a1 = d.a[0]; - a2 = d.a[1]; - } - function store() public returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { - X memory d; - d.x = 1; - d.s.x = 2; - d.s.y = 3; - d.s.z = 4; - d.a[0] = 5; - d.a[1] = 6; - m_x = d; - a = m_x.x; - x = m_x.s.x; - y = m_x.s.y; - z = m_x.s.z; - a1 = m_x.a[0]; - a2 = m_x.a[1]; - } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - - auto out = encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5), u256(6)); - ABI_CHECK(callContractFunction("load()"), out); - ABI_CHECK(callContractFunction("store()"), out); -} - -BOOST_AUTO_TEST_CASE(struct_constructor_nested) -{ - char const* sourceCode = R"( - contract C { - struct X { uint x1; uint x2; } - struct S { uint s1; uint[3] s2; X s3; } - S s; - constructor() public { - uint[3] memory s2; - s2[1] = 9; - s = S(1, s2, X(4, 5)); - } - function get() public returns (uint s1, uint[3] memory s2, uint x1, uint x2) - { - s1 = s.s1; - s2 = s.s2; - x1 = s.s3.x1; - x2 = s.s3.x2; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - auto out = encodeArgs(u256(1), u256(0), u256(9), u256(0), u256(4), u256(5)); - ABI_CHECK(callContractFunction("get()"), out); -} - BOOST_AUTO_TEST_CASE(calldata_struct_short) { char const* sourceCode = R"( @@ -4468,31 +4051,6 @@ BOOST_AUTO_TEST_CASE(calldata_struct_short) ABI_CHECK(callContractFunctionNoEncoding("f((uint256,uint256))", bytes()), encodeArgs()); } -BOOST_AUTO_TEST_CASE(calldata_struct_cleaning) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - struct S { uint8 a; bytes1 b; } - function f(S calldata s) external pure returns (uint256 a, bytes32 b) { - uint8 tmp1 = s.a; - bytes1 tmp2 = s.b; - assembly { - a := tmp1 - b := tmp2 - } - - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - // double check that the valid case goes through - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x12), bytes{0x34} + bytes(31,0)), encodeArgs(0x12, bytes{0x34} + bytes(31,0))); - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(0x1234), bytes{0x56, 0x78} + bytes(30,0)), encodeArgs()); - ABI_CHECK(callContractFunction("f((uint8,bytes1))", u256(-1), u256(-1)), encodeArgs()); -} - BOOST_AUTO_TEST_CASE(calldata_struct_function_type) { char const* sourceCode = R"( @@ -4518,144 +4076,38 @@ BOOST_AUTO_TEST_CASE(calldata_struct_function_type) ABI_CHECK(callContractFunctionNoEncoding("f((function))", fn_C_h), encodeArgs(23)); } -BOOST_AUTO_TEST_CASE(calldata_array_dynamic_bytes) +BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds) { char const* sourceCode = R"( pragma experimental ABIEncoderV2; contract C { - function f1(bytes[1] calldata a) external returns (uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2])); - } - function f2(bytes[1] calldata a, bytes[1] calldata b) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), b[0].length, uint8(b[0][0]), uint8(b[0][1])); - } - function g1(bytes[2] calldata a) external returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) { - return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])); - } - function g2(bytes[] calldata a) external returns (uint256[8] memory) { - return [a.length, a[0].length, uint8(a[0][0]), uint8(a[0][1]), a[1].length, uint8(a[1][0]), uint8(a[1][1]), uint8(a[1][2])]; + function f(bytes[] calldata a, uint256 i) external returns (uint) { + return uint8(a[0][i]); } } )"; compileAndRun(sourceCode, 0, "C"); - bytes bytes010203 = bytes{1,2,3}+bytes(29,0); - bytes bytes040506 = bytes{4,5,6}+bytes(29,0); - bytes bytes0102 = bytes{1,2}+bytes(30,0); - ABI_CHECK( - callContractFunction("f1(bytes[1])", 0x20, 0x20, 3, bytes010203), - encodeArgs(3, 1, 2, 3) - ); - ABI_CHECK( - callContractFunction("f2(bytes[1],bytes[1])", 0x40, 0xA0, 0x20, 3, bytes010203, 0x20, 2, bytes0102), - encodeArgs(3, 1, 2, 3, 2, 1, 2) - ); ABI_CHECK( - callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x80, 3, bytes010203, 3, bytes040506), - encodeArgs(3, 1, 2, 3, 3, 4, 5, 6) + callContractFunction("f(bytes[],uint256)", 0x40, 0, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs('a') ); - // same offset for both arrays ABI_CHECK( - callContractFunction("g1(bytes[2])", 0x20, 0x40, 0x40, 3, bytes010203), - encodeArgs(3, 1, 2, 3, 3, 1, 2, 3) + callContractFunction("f(bytes[],uint256)", 0x40, 1, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs('b') ); ABI_CHECK( - callContractFunction("g2(bytes[])", 0x20, 2, 0x40, 0x80, 2, bytes0102, 3, bytes040506), - encodeArgs(2, 2, 1, 2, 3, 4, 5, 6) + callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), + encodeArgs() ); } -BOOST_AUTO_TEST_CASE(calldata_bytes_array_to_memory) +BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) { - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes[] calldata a) external returns (uint, uint, bytes memory) { - bytes memory m = a[0]; - return (a.length, m.length, m); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs(1, 2, 0x60, 2, bytes{'a','b'} + bytes(30, 0)) - ); - - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, bytes(32, 'x')), - encodeArgs(1, 32, 0x60, 32, bytes(32, 'x')) - ); - bytes x_zero_a = bytes{'x'} + bytes(30, 0) + bytes{'a'}; - bytes a_zero_x = bytes{'a'} + bytes(30, 0) + bytes{'x'}; - bytes a_m_x = bytes{'a'} + bytes(30, 'm') + bytes{'x'}; - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, x_zero_a), - encodeArgs(1, 32, 0x60, 32, x_zero_a) - ); - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_zero_x), - encodeArgs(1, 32, 0x60, 32, a_zero_x) - ); - ABI_CHECK( - callContractFunction("f(bytes[])", 0x20, 1, 0x20, 32, a_m_x), - encodeArgs(1, 32, 0x60, 32, a_m_x) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(bytes[] calldata a, uint256 i) external returns (uint) { - return uint8(a[0][i]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 0, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs('a') - ); - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 1, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs('b') - ); - ABI_CHECK( - callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs() - ); -} - -BOOST_AUTO_TEST_CASE(calldata_string_array) -{ - char const* sourceCode = R"( - pragma experimental ABIEncoderV2; - contract C { - function f(string[] calldata a) external returns (uint, uint, uint, string memory) { - string memory s1 = a[0]; - bytes memory m1 = bytes(s1); - return (a.length, m1.length, uint8(m1[0]), s1); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - ABI_CHECK( - callContractFunction("f(string[])", 0x20, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), - encodeArgs(1, 2, 'a', 0x80, 2, bytes{'a', 'b'} + bytes(30, 0)) - ); -} - -BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional) -{ - vector> data { - { 0x0A01, 0x0A02, 0x0A03 }, - { 0x0B01, 0x0B02, 0x0B03, 0x0B04 } - }; + vector> data { + { 0x0A01, 0x0A02, 0x0A03 }, + { 0x0B01, 0x0B02, 0x0B03, 0x0B04 } + }; for (bool outerDynamicallySized: { true, false }) { @@ -4835,25 +4287,6 @@ BOOST_AUTO_TEST_CASE(initialise_string_constant) ABI_CHECK(callContractFunction("short()"), encodeDyn(shortStr)); } -BOOST_AUTO_TEST_CASE(string_bytes_conversion) -{ - char const* sourceCode = R"( - contract Test { - string s; - bytes b; - function f(string memory _s, uint n) public returns (byte) { - b = bytes(_s); - s = string(b); - return bytes(s)[n]; - } - function l() public returns (uint) { return bytes(s).length; } - } - )"; - compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction("f(string,uint256)", u256(0x40), u256(2), u256(6), string("abcdef")), encodeArgs("c")); - ABI_CHECK(callContractFunction("l()"), encodeArgs(u256(6))); -} - BOOST_AUTO_TEST_CASE(string_as_mapping_key) { char const* sourceCode = R"( @@ -5108,48 +4541,6 @@ BOOST_AUTO_TEST_CASE(library_stray_values) ABI_CHECK(callContractFunction("f(uint256)", u256(33)), encodeArgs(u256(42))); } -BOOST_AUTO_TEST_CASE(strings_in_struct) -{ - char const* sourceCode = R"( - contract buggystruct { - Buggy public bug; - - struct Buggy { - uint first; - uint second; - uint third; - string last; - } - - constructor() public { - bug = Buggy(10, 20, 30, "asdfghjkl"); - } - function getFirst() public returns (uint) - { - return bug.first; - } - function getSecond() public returns (uint) - { - return bug.second; - } - function getThird() public returns (uint) - { - return bug.third; - } - function getLast() public returns (string memory) - { - return bug.last; - } - } - )"; - compileAndRun(sourceCode); - string s = "asdfghjkl"; - ABI_CHECK(callContractFunction("getFirst()"), encodeArgs(u256(10))); - ABI_CHECK(callContractFunction("getSecond()"), encodeArgs(u256(20))); - ABI_CHECK(callContractFunction("getThird()"), encodeArgs(u256(30))); - ABI_CHECK(callContractFunction("getLast()"), encodeDyn(s)); -} - BOOST_AUTO_TEST_CASE(internal_types_in_library) { char const* sourceCode = R"( @@ -5641,27 +5032,6 @@ BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) } } -BOOST_AUTO_TEST_CASE(string_allocation_bug) -{ - char const* sourceCode = R"( - contract Sample - { - struct s { uint16 x; uint16 y; string a; string b;} - s[2] public p; - constructor() public { - s memory m; - m.x = 0xbbbb; - m.y = 0xcccc; - m.a = "hello"; - m.b = "world"; - p[0] = m; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("p(uint256)", 0), encodeArgs(u256(0xbbbb), u256(0xcccc), u256(0x80), u256(0xc0), u256(5), string("hello"), u256(5), string("world"))); -} - BOOST_AUTO_TEST_CASE(using_for_function_on_int) { char const* sourceCode = R"( @@ -5815,27 +5185,6 @@ BOOST_AUTO_TEST_CASE(inline_long_string_return) ABI_CHECK(callContractFunction("f()"), encodeDyn(strLong)); } -BOOST_AUTO_TEST_CASE(fixed_bytes_index_access) -{ - char const* sourceCode = R"( - contract C { - bytes16[] public data; - function f(bytes32 x) public returns (byte) { - return x[2]; - } - function g(bytes32 x) public returns (uint) { - data = [x[0], x[1], x[2]]; - data[0] = "12345"; - return uint(uint8(data[0][4])); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs("9")); - ABI_CHECK(callContractFunction("g(bytes32)", "789"), encodeArgs(u256(int('5')))); - ABI_CHECK(callContractFunction("data(uint256)", u256(1)), encodeArgs("8")); -} - BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) { // Test for a bug where higher order bits cleanup was not done for array index access. @@ -5852,47 +5201,6 @@ BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32); } -BOOST_AUTO_TEST_CASE(cleanup_bytes_types) -{ - // Checks that bytesXX types are properly cleaned before they are compared. - char const* sourceCode = R"( - contract C { - function f(bytes2 a, uint16 x) public returns (uint) { - if (a != "ab") return 1; - if (x != 0x0102) return 2; - if (bytes3(uint24(x)) != 0x000102) return 3; - return 0; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - // We input longer data on purpose. - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(bytes2,uint16)", string("abc"), u256(0x040102)), v2 ? encodeArgs() : encodeArgs(0)); -} -BOOST_AUTO_TEST_CASE(cleanup_address_types) -{ - // Checks that address types are properly cleaned before they are compared. - char const* sourceCode = R"( - contract C { - function f(address a) public returns (uint) { - if (a != 0x1234567890123456789012345678901234567890) return 1; - return 0; - } - function g(address payable a) public returns (uint) { - if (a != 0x1234567890123456789012345678901234567890) return 1; - return 0; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - // We input longer data on purpose. - ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); - ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); -} - BOOST_AUTO_TEST_CASE(failed_create) { char const* sourceCode = R"( @@ -6172,113 +5480,6 @@ BOOST_AUTO_TEST_CASE(return_external_function_type) // TODO: store bound internal library functions -BOOST_AUTO_TEST_CASE(shift_right_garbled) -{ - char const* sourceCode = R"( - contract C { - function f(uint8 a, uint8 b) public returns (uint) { - assembly { - a := 0xffffffff - } - // Higher bits should be cleared before the shift - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(0xf))); - ABI_CHECK(callContractFunction("f(uint8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(0xf))); -} - -BOOST_AUTO_TEST_CASE(shift_right_garbled_signed) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, uint8 b) public returns (int) { - assembly { - a := 0xfffffff0 - } - // Higher bits should be signextended before the shift - return a >> b; - } - function g(int8 a, uint8 b) public returns (int) { - assembly { - a := 0xf0 - } - // Higher bits should be signextended before the shift - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("f(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(3)), encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(4)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0xFF)), encodeArgs(u256(-1))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1003)), v2 ? encodeArgs() : encodeArgs(u256(-2))); - ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int8) -{ - char const* sourceCode = R"( - contract C { - function f(int8 a, int8 b) public returns (int8) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int8,int8)", u256(0x99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int16) -{ - char const* sourceCode = R"( - contract C { - function f(int16 a, int16 b) public returns (int16) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int16,int16)", u256(0xFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32) -{ - char const* sourceCode = R"( - contract C { - function f(int32 a, int32 b) public returns (int32) { - return a >> b; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - bool v2 = solidity::test::CommonOptions::get().useABIEncoderV2; - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(0)), v2 ? encodeArgs() : encodeArgs(u256(-103))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(1)), v2 ? encodeArgs() : encodeArgs(u256(-52))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(2)), v2 ? encodeArgs() : encodeArgs(u256(-26))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(4)), v2 ? encodeArgs() : encodeArgs(u256(-7))); - ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); -} - BOOST_AUTO_TEST_CASE(shift_bytes) { char const* sourceCode = R"( @@ -6653,33 +5854,6 @@ BOOST_AUTO_TEST_CASE(interface_contract) ABI_CHECK(callContractFunction("f(address)", recipient), encodeArgs(true)); } -BOOST_AUTO_TEST_CASE(multi_modifiers) -{ - // This triggered a bug in some version because the variable in the modifier was not - // unregistered correctly. - char const* sourceCode = R"( - contract C { - uint public x; - modifier m1 { - address a1 = msg.sender; - x++; - _; - } - function f1() m1() public { - x += 7; - } - function f2() m1() public { - x += 3; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f1()"), bytes()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(8))); - ABI_CHECK(callContractFunction("f2()"), bytes()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(12))); -} - BOOST_AUTO_TEST_CASE(bare_call_invalid_address) { char const* sourceCode = R"YY( @@ -6840,110 +6014,6 @@ BOOST_AUTO_TEST_CASE(bare_call_return_data) } } -BOOST_AUTO_TEST_CASE(delegatecall_return_value) -{ - if (solidity::test::CommonOptions::get().evmVersion().supportsReturndata()) - { - char const* sourceCode = R"DELIMITER( - contract C { - uint value; - function set(uint _value) external { - value = _value; - } - function get() external view returns (uint) { - return value; - } - function get_delegated() external returns (bool, bytes memory) { - return address(this).delegatecall(abi.encodeWithSignature("get()")); - } - function assert0() external view { - assert(value == 0); - } - function assert0_delegated() external returns (bool, bytes memory) { - return address(this).delegatecall(abi.encodeWithSignature("assert0()")); - } - } - )DELIMITER"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(1), 0x40, 0x00)); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 0x00)); - ABI_CHECK(callContractFunction("set(uint256)", u256(1)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0), 0x40, 0x00)); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 1)); - ABI_CHECK(callContractFunction("set(uint256)", u256(42)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0), 0x40, 0x00)); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1), 0x40, 0x20, 42)); - } - else - { - char const* sourceCode = R"DELIMITER( - contract C { - uint value; - function set(uint _value) external { - value = _value; - } - function get() external view returns (uint) { - return value; - } - function get_delegated() external returns (bool) { - (bool success,) = address(this).delegatecall(abi.encodeWithSignature("get()")); - return success; - } - function assert0() external view { - assert(value == 0); - } - function assert0_delegated() external returns (bool) { - (bool success,) = address(this).delegatecall(abi.encodeWithSignature("assert0()")); - return success; - } - } - )DELIMITER"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("set(uint256)", u256(1)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1))); - ABI_CHECK(callContractFunction("set(uint256)", u256(42)), encodeArgs()); - ABI_CHECK(callContractFunction("get()"), encodeArgs(u256(42))); - ABI_CHECK(callContractFunction("assert0_delegated()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("get_delegated()"), encodeArgs(u256(1))); - } -} - -BOOST_AUTO_TEST_CASE(function_types_sig) -{ - char const* sourceCode = R"( - contract C { - uint public x; - function f() public pure returns (bytes4) { - return this.f.selector; - } - function g() public returns (bytes4) { - function () pure external returns (bytes4) fun = this.f; - return fun.selector; - } - function h() public returns (bytes4) { - function () pure external returns (bytes4) fun = this.f; - return fun.selector; - } - function i() public pure returns (bytes4) { - return this.x.selector; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(asString(FixedHash<4>(util::keccak256("f()")).asBytes()))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(asString(FixedHash<4>(util::keccak256("f()")).asBytes()))); - ABI_CHECK(callContractFunction("h()"), encodeArgs(asString(FixedHash<4>(util::keccak256("f()")).asBytes()))); - ABI_CHECK(callContractFunction("i()"), encodeArgs(asString(FixedHash<4>(util::keccak256("x()")).asBytes()))); -} - BOOST_AUTO_TEST_CASE(abi_encodePacked) { char const* sourceCode = R"( @@ -7488,344 +6558,6 @@ BOOST_AUTO_TEST_CASE(abi_encode_with_signaturev2) ABI_CHECK(callContractFunction("f4()"), expectation); } -BOOST_AUTO_TEST_CASE(abi_encode_empty_string) -{ - char const* sourceCode = R"( - // Tests that this will not end up using a "bytes0" type - // (which would assert) - contract C { - function f() public pure returns (bytes memory, bytes memory) { - return (abi.encode(""), abi.encodePacked("")); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - if (!solidity::test::CommonOptions::get().useABIEncoderV2) - { - // ABI Encoder V2 has slightly different padding, tested below. - ABI_CHECK(callContractFunction("f()"), encodeArgs( - 0x40, 0xc0, - 0x60, 0x20, 0x00, 0x00, - 0x00 - )); - } -} - -BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) -{ - char const* sourceCode = R"( - contract C { - uint x; - function f() public returns (uint) { - x = 3; - return 1; - } - } - interface CView { - function f() view external returns (uint); - } - interface CPure { - function f() pure external returns (uint); - } - contract D { - function f() public returns (uint) { - return (new C()).f(); - } - function fview() public returns (uint) { - return (CView(address(new C()))).f(); - } - function fpure() public returns (uint) { - return (CPure(address(new C()))).f(); - } - } - )"; - compileAndRun(sourceCode, 0, "D"); - // This should work (called via CALL) - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); - if (solidity::test::CommonOptions::get().evmVersion().hasStaticCall()) - { - // These should throw (called via STATICCALL) - ABI_CHECK(callContractFunction("fview()"), encodeArgs()); - ABI_CHECK(callContractFunction("fpure()"), encodeArgs()); - } - else - { - ABI_CHECK(callContractFunction("fview()"), encodeArgs(1)); - ABI_CHECK(callContractFunction("fpure()"), encodeArgs(1)); - } -} - -BOOST_AUTO_TEST_CASE(bitwise_shifting_constantinople) -{ - if (!solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting()) - return; - char const* sourceCode = R"( - contract C { - function shl(uint a, uint b) public returns (uint c) { - assembly { - c := shl(b, a) - } - } - function shr(uint a, uint b) public returns (uint c) { - assembly { - c := shr(b, a) - } - } - function sar(uint a, uint b) public returns (uint c) { - assembly { - c := sar(b, a) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256(1), u256(2)) == encodeArgs(u256(4))); - BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"))); - BOOST_CHECK(callContractFunction("shl(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256(3), u256(1)) == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(255)) == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shr(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256(3), u256(1)) == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(1)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(255)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("sar(uint256,uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), u256(256)) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - ) -} - -BOOST_AUTO_TEST_CASE(bitwise_shifting_constants_constantinople) -{ - if (!solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting()) - return; - char const* sourceCode = R"( - contract C { - function shl_1() public returns (bool) { - uint c; - assembly { - c := shl(2, 1) - } - assert(c == 4); - return true; - } - function shl_2() public returns (bool) { - uint c; - assembly { - c := shl(1, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - } - assert(c == 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe); - return true; - } - function shl_3() public returns (bool) { - uint c; - assembly { - c := shl(256, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - } - assert(c == 0); - return true; - } - function shr_1() public returns (bool) { - uint c; - assembly { - c := shr(1, 3) - } - assert(c == 1); - return true; - } - function shr_2() public returns (bool) { - uint c; - assembly { - c := shr(1, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - } - assert(c == 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); - return true; - } - function shr_3() public returns (bool) { - uint c; - assembly { - c := shr(256, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) - } - assert(c == 0); - return true; - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("shl_1()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shl_2()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shl_3()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shr_1()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shr_2()") == encodeArgs(u256(1))); - BOOST_CHECK(callContractFunction("shr_3()") == encodeArgs(u256(1))); - ) -} - -BOOST_AUTO_TEST_CASE(bitwise_shifting_constantinople_combined) -{ - if (!solidity::test::CommonOptions::get().evmVersion().hasBitwiseShifting()) - return; - char const* sourceCode = R"( - contract C { - function shl_zero(uint a) public returns (uint c) { - assembly { - c := shl(0, a) - } - } - function shr_zero(uint a) public returns (uint c) { - assembly { - c := shr(0, a) - } - } - function sar_zero(uint a) public returns (uint c) { - assembly { - c := sar(0, a) - } - } - - function shl_large(uint a) public returns (uint c) { - assembly { - c := shl(0x110, a) - } - } - function shr_large(uint a) public returns (uint c) { - assembly { - c := shr(0x110, a) - } - } - function sar_large(uint a) public returns (uint c) { - assembly { - c := sar(0x110, a) - } - } - - function shl_combined(uint a) public returns (uint c) { - assembly { - c := shl(4, shl(12, a)) - } - } - function shr_combined(uint a) public returns (uint c) { - assembly { - c := shr(4, shr(12, a)) - } - } - function sar_combined(uint a) public returns (uint c) { - assembly { - c := sar(4, sar(12, a)) - } - } - - function shl_combined_large(uint a) public returns (uint c) { - assembly { - c := shl(0xd0, shl(0x40, a)) - } - } - function shl_combined_overflow(uint a) public returns (uint c) { - assembly { - c := shl(0x01, shl(not(0x00), a)) - } - } - function shr_combined_large(uint a) public returns (uint c) { - assembly { - c := shr(0xd0, shr(0x40, a)) - } - } - function shr_combined_overflow(uint a) public returns (uint c) { - assembly { - c := shr(0x01, shr(not(0x00), a)) - } - } - function sar_combined_large(uint a) public returns (uint c) { - assembly { - c := sar(0xd0, sar(0x40, a)) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - - BOOST_CHECK(callContractFunction("shl_zero(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_zero(uint256)", u256("0xffff")) == encodeArgs(u256("0xffff"))); - BOOST_CHECK(callContractFunction("shl_zero(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("shr_zero(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_zero(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("sar_zero(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_zero(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - - BOOST_CHECK(callContractFunction("shl_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_large(uint256)", u256("0xffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_large(uint256)", u256("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - - BOOST_CHECK(callContractFunction("shl_combined(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_combined(uint256)", u256("0xffff")) == encodeArgs(u256("0xffff0000"))); - BOOST_CHECK(callContractFunction("shl_combined(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000"))); - BOOST_CHECK(callContractFunction("shr_combined(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_combined(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("sar_combined(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_combined(uint256)", u256("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0x00007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - BOOST_CHECK(callContractFunction("sar_combined(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - - BOOST_CHECK(callContractFunction("shl_combined_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_combined_large(uint256)", u256("0xffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_combined_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shl_combined_overflow(uint256)", u256(2)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_combined_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_combined_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("shr_combined_overflow(uint256)", u256(2)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_combined_large(uint256)", u256(0)) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_combined_large(uint256)", u256("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256(0))); - BOOST_CHECK(callContractFunction("sar_combined_large(uint256)", u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) == encodeArgs(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))); - ) -} - -BOOST_AUTO_TEST_CASE(abi_decode_simple) -{ - char const* sourceCode = R"( - contract C { - function f(bytes memory data) public pure returns (uint, bytes memory) { - return abi.decode(data, (uint, bytes)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); -} - -BOOST_AUTO_TEST_CASE(abi_decode_simple_storage) -{ - char const* sourceCode = R"( - contract C { - bytes data; - function f(bytes memory _data) public returns (uint, bytes memory) { - data = _data; - return abi.decode(data, (uint, bytes)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); -} - -BOOST_AUTO_TEST_CASE(abi_decode_calldata) -{ - char const* sourceCode = R"( - contract C { - function f(bytes calldata data) external pure returns (uint, bytes memory r) { - return abi.decode(data, (uint, bytes)); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bytes)", 0x20, 0x20 * 4, 33, 0x40, 7, "abcdefg"), encodeArgs(33, 0x40, 7, "abcdefg")); -} - BOOST_AUTO_TEST_CASE(code_access) { char const* sourceCode = R"( diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol b/test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol new file mode 100644 index 000000000000..6b6e55e02241 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol @@ -0,0 +1,11 @@ +contract C { + function f(bytes calldata data) + external + pure + returns (uint256, bytes memory r) + { + return abi.decode(data, (uint256, bytes)); + } +} +// ---- +// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_simple.sol b/test/libsolidity/semanticTests/extracted/abi_decode_simple.sol new file mode 100644 index 000000000000..9ae6602f310f --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_simple.sol @@ -0,0 +1,7 @@ +contract C { + function f(bytes memory data) public pure returns (uint256, bytes memory) { + return abi.decode(data, (uint256, bytes)); + } +} +// ---- +// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol b/test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol new file mode 100644 index 000000000000..af37480a3798 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol @@ -0,0 +1,10 @@ +contract C { + bytes data; + + function f(bytes memory _data) public returns (uint256, bytes memory) { + data = _data; + return abi.decode(data, (uint256, bytes)); + } +} +// ---- +// f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol b/test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol new file mode 100644 index 000000000000..6ca284908fa2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol @@ -0,0 +1,11 @@ +// Tests that this will not end up using a "bytes0" type +// (which would assert) +contract C { + function f() public pure returns (bytes memory, bytes memory) { + return (abi.encode(""), abi.encodePacked("")); + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f() -> 0x40, 0xc0, 0x60, 0x20, 0x0, 0x0, 0x0 diff --git a/test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol new file mode 100644 index 000000000000..9cec148c7b75 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol @@ -0,0 +1,18 @@ +contract Test { + uint24[3][] public data; + + function set(uint24[3][] memory _data) public returns (uint256) { + data = _data; + return data.length; + } + + function get() public returns (uint24[3][] memory) { + return data; + } +} +// ---- +// set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06 +// data(uint256,uint256): 0x02, 0x02 -> 0x09 +// data(uint256,uint256): 0x05, 0x01 -> 0x11 +// data(uint256,uint256): 0x06, 0x00 -> FAILURE +// get() -> 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 diff --git a/test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol b/test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol new file mode 100644 index 000000000000..d21bcc53f3c3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol @@ -0,0 +1,13 @@ +contract Test { + function set(uint24[3][] memory _data, uint256 a, uint256 b) + public + returns (uint256 l, uint256 e) + { + l = _data.length; + e = _data[a][b]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(uint24[3][],uint256,uint256): 0x60, 0x03, 0x02, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06, 0x0c diff --git a/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol b/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol new file mode 100644 index 000000000000..2fc479d0e10a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol @@ -0,0 +1,9 @@ +contract C { + bytes32 constant x = keccak256("abc"); + + function f() public returns (bytes32) { + return x; + } +} +// ---- +// f() -> 0x4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45 diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol new file mode 100644 index 000000000000..c6ada8c6a3d1 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol @@ -0,0 +1,34 @@ +contract C { + function shl(uint256 a, uint256 b) public returns (uint256 c) { + assembly { + c := shl(b, a) + } + } + + function shr(uint256 a, uint256 b) public returns (uint256 c) { + assembly { + c := shr(b, a) + } + } + + function sar(uint256 a, uint256 b) public returns (uint256 c) { + assembly { + c := sar(b, a) + } + } +} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// shl(uint256,uint256): 0x01, 0x02 -> 0x04 +// shl(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x01 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// shl(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x100 -> 0x00 +// shr(uint256,uint256): 0x03, 0x01 -> 0x01 +// shr(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x01 -> 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// shr(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0xff -> 0x01 +// shr(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x100 -> 0x00 +// sar(uint256,uint256): 0x03, 0x01 -> 0x01 +// sar(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// sar(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0xff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// sar(uint256,uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x100 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol new file mode 100644 index 000000000000..6cacbe30034e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol @@ -0,0 +1,122 @@ +contract C { + function shl_zero(uint256 a) public returns (uint256 c) { + assembly { + c := shl(0, a) + } + } + + function shr_zero(uint256 a) public returns (uint256 c) { + assembly { + c := shr(0, a) + } + } + + function sar_zero(uint256 a) public returns (uint256 c) { + assembly { + c := sar(0, a) + } + } + + function shl_large(uint256 a) public returns (uint256 c) { + assembly { + c := shl(0x110, a) + } + } + + function shr_large(uint256 a) public returns (uint256 c) { + assembly { + c := shr(0x110, a) + } + } + + function sar_large(uint256 a) public returns (uint256 c) { + assembly { + c := sar(0x110, a) + } + } + + function shl_combined(uint256 a) public returns (uint256 c) { + assembly { + c := shl(4, shl(12, a)) + } + } + + function shr_combined(uint256 a) public returns (uint256 c) { + assembly { + c := shr(4, shr(12, a)) + } + } + + function sar_combined(uint256 a) public returns (uint256 c) { + assembly { + c := sar(4, sar(12, a)) + } + } + + function shl_combined_large(uint256 a) public returns (uint256 c) { + assembly { + c := shl(0xd0, shl(0x40, a)) + } + } + + function shl_combined_overflow(uint256 a) public returns (uint256 c) { + assembly { + c := shl(0x01, shl(not(0x00), a)) + } + } + + function shr_combined_large(uint256 a) public returns (uint256 c) { + assembly { + c := shr(0xd0, shr(0x40, a)) + } + } + + function shr_combined_overflow(uint256 a) public returns (uint256 c) { + assembly { + c := shr(0x01, shr(not(0x00), a)) + } + } + + function sar_combined_large(uint256 a) public returns (uint256 c) { + assembly { + c := sar(0xd0, sar(0x40, a)) + } + } +} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// shl_zero(uint256): 0x00 -> 0x00 +// shl_zero(uint256): 0xffff -> 0xffff +// shl_zero(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// shr_zero(uint256): 0x00 -> 0x00 +// shr_zero(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// sar_zero(uint256): 0x00 -> 0x00 +// sar_zero(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// shl_large(uint256): 0x00 -> 0x00 +// shl_large(uint256): 0xffff -> 0x00 +// shl_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// shr_large(uint256): 0x00 -> 0x00 +// shr_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// sar_large(uint256): 0x00 -> 0x00 +// sar_large(uint256): 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// sar_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// shl_combined(uint256): 0x00 -> 0x00 +// shl_combined(uint256): 0xffff -> 0xffff0000 +// shl_combined(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000 +// shr_combined(uint256): 0x00 -> 0x00 +// shr_combined(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// sar_combined(uint256): 0x00 -> 0x00 +// sar_combined(uint256): 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// sar_combined(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// shl_combined_large(uint256): 0x00 -> 0x00 +// shl_combined_large(uint256): 0xffff -> 0x00 +// shl_combined_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// shl_combined_overflow(uint256): 0x02 -> 0x00 +// shr_combined_large(uint256): 0x00 -> 0x00 +// shr_combined_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// shr_combined_overflow(uint256): 0x02 -> 0x00 +// sar_combined_large(uint256): 0x00 -> 0x00 +// sar_combined_large(uint256): 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0x00 +// sar_combined_large(uint256): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol new file mode 100644 index 000000000000..bbc5ddaa4b87 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol @@ -0,0 +1,83 @@ +contract C { + function shl_1() public returns (bool) { + uint256 c; + assembly { + c := shl(2, 1) + } + assert(c == 4); + return true; + } + + function shl_2() public returns (bool) { + uint256 c; + assembly { + c := shl( + 1, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ) + } + assert( + c == + 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe + ); + return true; + } + + function shl_3() public returns (bool) { + uint256 c; + assembly { + c := shl( + 256, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ) + } + assert(c == 0); + return true; + } + + function shr_1() public returns (bool) { + uint256 c; + assembly { + c := shr(1, 3) + } + assert(c == 1); + return true; + } + + function shr_2() public returns (bool) { + uint256 c; + assembly { + c := shr( + 1, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ) + } + assert( + c == + 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ); + return true; + } + + function shr_3() public returns (bool) { + uint256 c; + assembly { + c := shr( + 256, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ) + } + assert(c == 0); + return true; + } +} +// ==== +// EVMVersion: >=constantinople +// compileViaYul: also +// ---- +// shl_1() -> 0x01 +// shl_2() -> 0x01 +// shl_3() -> 0x01 +// shr_1() -> 0x01 +// shr_2() -> 0x01 +// shr_3() -> 0x01 diff --git a/test/libsolidity/semanticTests/extracted/bool_conversion.sol b/test/libsolidity/semanticTests/extracted/bool_conversion.sol new file mode 100644 index 000000000000..20f594764339 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bool_conversion.sol @@ -0,0 +1,23 @@ +contract C { + function f(bool _b) public returns (uint256) { + if (_b) return 1; + else return 0; + } + + function g(bool _in) public returns (bool _out) { + _out = _in; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(bool): 0x0 -> 0x0 +// f(bool): 0x1 -> 0x1 +// f(bool): 0x2 -> 0x1 +// f(bool): 0x3 -> 0x1 +// f(bool): 0xff -> 0x1 +// g(bool): 0x0 -> 0x0 +// g(bool): 0x1 -> 0x1 +// g(bool): 0x2 -> 0x1 +// g(bool): 0x3 -> 0x1 +// g(bool): 0xff -> 0x1 diff --git a/test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol b/test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol new file mode 100644 index 000000000000..a8fd898333c4 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(bool _b) public returns (uint256) { + if (_b) return 1; + else return 0; + } + + function g(bool _in) public returns (bool _out) { + _out = _in; + } +} +// ---- +// f(bool): 0x0 -> 0x0 +// f(bool): 0x1 -> 0x1 +// f(bool): 0x2 -> FAILURE +// f(bool): 0x3 -> FAILURE +// f(bool): 0xff -> FAILURE +// g(bool): 0x0 -> 0x0 +// g(bool): 0x1 -> 0x1 +// g(bool): 0x2 -> FAILURE +// g(bool): 0x3 -> FAILURE +// g(bool): 0xff -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol b/test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol new file mode 100644 index 000000000000..5b7fd7ac3f2d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol @@ -0,0 +1,13 @@ +contract Test { + function set(bytes memory _data, uint256 i) + public + returns (uint256 l, bytes1 c) + { + l = _data.length; + c = _data[i]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(bytes,uint256): 0x40, 0x03, 0x08, "abcdefgh" -> 0x08, "d" diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol new file mode 100644 index 000000000000..c2c2fa70a678 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol @@ -0,0 +1,74 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f1(bytes[1] calldata a) + external + returns (uint256, uint256, uint256, uint256) + { + return (a[0].length, uint8(a[0][0]), uint8(a[0][1]), uint8(a[0][2])); + } + + function f2(bytes[1] calldata a, bytes[1] calldata b) + external + returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256) + { + return ( + a[0].length, + uint8(a[0][0]), + uint8(a[0][1]), + uint8(a[0][2]), + b[0].length, + uint8(b[0][0]), + uint8(b[0][1]) + ); + } + + function g1(bytes[2] calldata a) + external + returns ( + uint256, + uint256, + uint256, + uint256, + uint256, + uint256, + uint256, + uint256 + ) + { + return ( + a[0].length, + uint8(a[0][0]), + uint8(a[0][1]), + uint8(a[0][2]), + a[1].length, + uint8(a[1][0]), + uint8(a[1][1]), + uint8(a[1][2]) + ); + } + + function g2(bytes[] calldata a) external returns (uint256[8] memory) { + return [ + a.length, + a[0].length, + uint8(a[0][0]), + uint8(a[0][1]), + a[1].length, + uint8(a[1][0]), + uint8(a[1][1]), + uint8(a[1][2]) + ]; + } +} + +// found expectation comments: +// same offset for both arrays @ ABI_CHECK( + +// ---- +// f1(bytes[1]): 0x20, 0x20, 0x3, hex"0102030000000000000000000000000000000000000000000000000000000000" -> 0x3, 0x1, 0x2, 0x3 +// f2(bytes[1],bytes[1]): 0x40, 0xa0, 0x20, 0x3, hex"0102030000000000000000000000000000000000000000000000000000000000", 0x20, 0x2, hex"0102000000000000000000000000000000000000000000000000000000000000" -> 0x3, 0x1, 0x2, 0x3, 0x2, 0x1, 0x2 +// g1(bytes[2]): 0x20, 0x40, 0x80, 0x3, hex"0102030000000000000000000000000000000000000000000000000000000000", 0x3, hex"0405060000000000000000000000000000000000000000000000000000000000" -> 0x3, 0x1, 0x2, 0x3, 0x3, 0x4, 0x5, 0x6 +// g1(bytes[2]): 0x20, 0x40, 0x40, 0x3, hex"0102030000000000000000000000000000000000000000000000000000000000" -> 0x3, 0x1, 0x2, 0x3, 0x3, 0x1, 0x2, 0x3 +// g2(bytes[]): 0x20, 0x2, 0x40, 0x80, 0x2, hex"0102000000000000000000000000000000000000000000000000000000000000", 0x3, hex"0405060000000000000000000000000000000000000000000000000000000000" -> 0x2, 0x2, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 diff --git a/test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol b/test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol new file mode 100644 index 000000000000..04b2ed15d541 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(bytes[] calldata a) + external + returns (uint256, uint256, bytes memory) + { + bytes memory m = a[0]; + return (a.length, m.length, m); + } +} +// ---- +// f(bytes[]): 0x20, 0x1, 0x20, 0x2, hex"6162000000000000000000000000000000000000000000000000000000000000" -> 0x1, 0x2, 0x60, 0x2, hex"6162000000000000000000000000000000000000000000000000000000000000" +// f(bytes[]): 0x20, 0x1, 0x20, 0x20, hex"7878787878787878787878787878787878787878787878787878787878787878" -> 0x1, 0x20, 0x60, 0x20, hex"7878787878787878787878787878787878787878787878787878787878787878" +// f(bytes[]): 0x20, 0x1, 0x20, 0x20, hex"7800000000000000000000000000000000000000000000000000000000000061" -> 0x1, 0x20, 0x60, 0x20, hex"7800000000000000000000000000000000000000000000000000000000000061" +// f(bytes[]): 0x20, 0x1, 0x20, 0x20, hex"6100000000000000000000000000000000000000000000000000000000000078" -> 0x1, 0x20, 0x60, 0x20, hex"6100000000000000000000000000000000000000000000000000000000000078" +// f(bytes[]): 0x20, 0x1, 0x20, 0x20, hex"616d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d78" -> 0x1, 0x20, 0x60, 0x20, hex"616d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d6d78" diff --git a/test/libsolidity/semanticTests/extracted/calldata_string_array.sol b/test/libsolidity/semanticTests/extracted/calldata_string_array.sol new file mode 100644 index 000000000000..ae7d1e2ef804 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_string_array.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(string[] calldata a) + external + returns (uint256, uint256, uint256, string memory) + { + string memory s1 = a[0]; + bytes memory m1 = bytes(s1); + return (a.length, m1.length, uint8(m1[0]), s1); + } +} +// ---- +// f(string[]): 0x20, 0x1, 0x20, 0x2, hex"6162000000000000000000000000000000000000000000000000000000000000" -> 1, 2, 97, 0x80, 2, "ab" diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol b/test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol new file mode 100644 index 000000000000..dbf6e44405e2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol @@ -0,0 +1,22 @@ +pragma experimental ABIEncoderV2; + + +contract C { + struct S { + uint8 a; + bytes1 b; + } + + function f(S calldata s) external pure returns (uint256 a, bytes32 b) { + uint8 tmp1 = s.a; + bytes1 tmp2 = s.b; + assembly { + a := tmp1 + b := tmp2 + } + } +} +// ---- +// f((uint8,bytes1)): 0x12, hex"3400000000000000000000000000000000000000000000000000000000000000" -> 0x12, hex"3400000000000000000000000000000000000000000000000000000000000000" # double check that the valid case goes through # +// f((uint8,bytes1)): 0x1234, hex"5678000000000000000000000000000000000000000000000000000000000000" -> FAILURE +// f((uint8,bytes1)): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types.sol b/test/libsolidity/semanticTests/extracted/cleanup_address_types.sol new file mode 100644 index 000000000000..c94cfc776c7d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_address_types.sol @@ -0,0 +1,17 @@ +// Checks that address types are properly cleaned before they are compared. +contract C { + function f(address a) public returns (uint256) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; + } + + function g(address payable a) public returns (uint256) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(address): 0xffff1234567890123456789012345678901234567890 -> 0x0 # We input longer data on purpose.# +// g(address): 0xffff1234567890123456789012345678901234567890 -> 0x0 diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol b/test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol new file mode 100644 index 000000000000..beff156f757a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol @@ -0,0 +1,18 @@ +pragma experimental ABIEncoderV2; + + +// Checks that address types are properly cleaned before they are compared. +contract C { + function f(address a) public returns (uint256) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; + } + + function g(address payable a) public returns (uint256) { + if (a != 0x1234567890123456789012345678901234567890) return 1; + return 0; + } +} +// ---- +// f(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE # We input longer data on purpose.# +// g(address): 0xffff1234567890123456789012345678901234567890 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol new file mode 100644 index 000000000000..32b90748e805 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol @@ -0,0 +1,13 @@ +// Checks that bytesXX types are properly cleaned before they are compared. +contract C { + function f(bytes2 a, uint16 x) public returns (uint256) { + if (a != "ab") return 1; + if (x != 0x0102) return 2; + if (bytes3(uint24(x)) != 0x000102) return 3; + return 0; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(bytes2,uint16): "abc", 0x40102 -> 0x0 # We input longer data on purpose. # diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol new file mode 100644 index 000000000000..5adc97378754 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; + + +// Checks that bytesXX types are properly cleaned before they are compared. +contract C { + function f(bytes2 a, uint16 x) public returns (uint256) { + if (a != "ab") return 1; + if (x != 0x0102) return 2; + if (bytes3(uint24(x)) != 0x000102) return 3; + return 0; + } +} +// ---- +// f(bytes2,uint16): "abc", 0x40102 -> FAILURE # We input longer data on purpose. # diff --git a/test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol b/test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol new file mode 100644 index 000000000000..ffa22b8a27ea --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol @@ -0,0 +1,37 @@ +contract C { + uint256 value; + + function set(uint256 _value) external { + value = _value; + } + + function get() external view returns (uint256) { + return value; + } + + function get_delegated() external returns (bool, bytes memory) { + return address(this).delegatecall(abi.encodeWithSignature("get()")); + } + + function assert0() external view { + assert(value == 0); + } + + function assert0_delegated() external returns (bool, bytes memory) { + return address(this).delegatecall(abi.encodeWithSignature("assert0()")); + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// get() -> 0x00 +// assert0_delegated() -> 0x01, 0x40, 0x0 +// get_delegated() -> 0x01, 0x40, 0x20, 0x0 +// set(uint256): 0x01 -> +// get() -> 0x01 +// assert0_delegated() -> 0x00, 0x40, 0x0 +// get_delegated() -> 0x01, 0x40, 0x20, 0x1 +// set(uint256): 0x2a -> +// get() -> 0x2a +// assert0_delegated() -> 0x00, 0x40, 0x0 +// get_delegated() -> 0x01, 0x40, 0x20, 0x2a diff --git a/test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol b/test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol new file mode 100644 index 000000000000..498449d17d1b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol @@ -0,0 +1,39 @@ +contract C { + uint256 value; + + function set(uint256 _value) external { + value = _value; + } + + function get() external view returns (uint256) { + return value; + } + + function get_delegated() external returns (bool) { + (bool success,) = address(this).delegatecall(abi.encodeWithSignature("get()")); + return success; + } + + function assert0() external view { + assert(value == 0); + } + + function assert0_delegated() external returns (bool) { + (bool success,) = address(this).delegatecall(abi.encodeWithSignature("assert0()")); + return success; + } +} +// ==== +// EVMVersion: 0x00 +// assert0_delegated() -> true +// get_delegated() -> true +// set(uint256): 0x01 -> +// get() -> 0x01 +// assert0_delegated() -> false +// get_delegated() -> true +// set(uint256): 0x2a -> +// get() -> 0x2a +// assert0_delegated() -> false +// get_delegated() -> true diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol b/test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol new file mode 100644 index 000000000000..b65a3d254d54 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol @@ -0,0 +1,45 @@ +contract c { + struct Data { + uint256 x; + uint256 y; + } + Data[2**10] data; + uint256[2**10 + 3] ids; + + function setIDStatic(uint256 id) public { + ids[2] = id; + } + + function setID(uint256 index, uint256 id) public { + ids[index] = id; + } + + function setData(uint256 index, uint256 x, uint256 y) public { + data[index].x = x; + data[index].y = y; + } + + function getID(uint256 index) public returns (uint256) { + return ids[index]; + } + + function getData(uint256 index) public returns (uint256 x, uint256 y) { + x = data[index].x; + y = data[index].y; + } + + function getLengths() public returns (uint256 l1, uint256 l2) { + l1 = data.length; + l2 = ids.length; + } +} +// ---- +// setIDStatic(uint256): 0xb -> +// getID(uint256): 0x2 -> 0xb +// setID(uint256,uint256): 0x7, 0x8 -> +// getID(uint256): 0x7 -> 0x8 +// setData(uint256,uint256,uint256): 0x7, 0x8, 0x9 -> +// setData(uint256,uint256,uint256): 0x8, 0xa, 0xb -> +// getData(uint256): 0x7 -> 0x8, 0x9 +// getData(uint256): 0x8 -> 0xa, 0xb +// getLengths() -> 0x400, 0x403 diff --git a/test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol b/test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol new file mode 100644 index 000000000000..9ab74eaf363a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol @@ -0,0 +1,17 @@ +contract C { + bytes16[] public data; + + function f(bytes32 x) public returns (bytes1) { + return x[2]; + } + + function g(bytes32 x) public returns (uint256) { + data = [x[0], x[1], x[2]]; + data[0] = "12345"; + return uint256(uint8(data[0][4])); + } +} +// ---- +// f(bytes32): "789" -> "9" +// g(bytes32): "789" -> 0x35 +// data(uint256): 0x01 -> "8" diff --git a/test/libsolidity/semanticTests/extracted/function_types_sig.sol b/test/libsolidity/semanticTests/extracted/function_types_sig.sol new file mode 100644 index 000000000000..2e771032bc7e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/function_types_sig.sol @@ -0,0 +1,26 @@ +contract C { + uint256 public x; + + function f() public pure returns (bytes4) { + return this.f.selector; + } + + function g() public returns (bytes4) { + function () pure external returns (bytes4) fun = this.f; + return fun.selector; + } + + function h() public returns (bytes4) { + function () pure external returns (bytes4) fun = this.f; + return fun.selector; + } + + function i() public pure returns (bytes4) { + return this.x.selector; + } +} +// ---- +// f() -> 0x26121ff000000000000000000000000000000000000000000000000000000000 +// g() -> 0x26121ff000000000000000000000000000000000000000000000000000000000 +// h() -> 0x26121ff000000000000000000000000000000000000000000000000000000000 +// i() -> 0x0c55699c00000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol b/test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol new file mode 100644 index 000000000000..91a26945cd59 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol @@ -0,0 +1,12 @@ +contract c { + bytes data; + + function foo() public returns (bytes32) { + data.push("x"); + data.push("y"); + data.push("z"); + return keccak256(abi.encodePacked("b", keccak256(data), "a")); + } +} +// ---- +// foo() -> 0xb338eefce206f9f57b83aa738deecd5326dc4b72dd81ee6a7c621a6facb7acdc diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol new file mode 100644 index 000000000000..972aee839e0e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol @@ -0,0 +1,7 @@ +contract c { + function foo(uint256 a, uint256 b, uint256 c) public returns (bytes32 d) { + d = keccak256(abi.encodePacked(a, b, c)); + } +} +// ---- +// foo(uint256,uint256,uint256): 0xa, 0xc, 0xd -> 0xbc740a98aae5923e8f04c9aa798c9ee82f69e319997699f2782c40828db9fd81 diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol new file mode 100644 index 000000000000..01397f55f85e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol @@ -0,0 +1,7 @@ +contract c { + function foo(uint256 a, uint16 b) public returns (bytes32 d) { + d = keccak256(abi.encodePacked(a, b, uint8(145))); + } +} +// ---- +// foo(uint256,uint16): 0xa, 0xc -> 0x88acd45f75907e7c560318bc1a5249850a0999c4896717b1167d05d116e6dbad diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol new file mode 100644 index 000000000000..b157178fb857 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol @@ -0,0 +1,12 @@ +contract c { + function foo() public returns (bytes32 d) { + d = keccak256("foo"); + } + + function bar(uint256 a, uint16 b) public returns (bytes32 d) { + d = keccak256(abi.encodePacked(a, b, uint8(145), "foo")); + } +} +// ---- +// foo() -> 0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d +// bar(uint256,uint16): 0xa, 0xc -> 0x6990f36476dc412b1c4baa48e2d9f4aa4bb313f61fda367c8fdbbb2232dc6146 diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol b/test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol new file mode 100644 index 000000000000..be824b759fc6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol @@ -0,0 +1,19 @@ +contract Test { + uint24[3][][4] data; + + function set(uint24[3][][4] memory x) + internal + returns (uint24[3][][4] memory) + { + x[1][2][2] = 1; + x[1][3][2] = 7; + return x; + } + + function f() public returns (uint24[3][] memory) { + while (data[1].length < 4) data[1].push(); + return set(data)[1]; + } +} +// ---- +// f() -> 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07 diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol b/test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol new file mode 100644 index 000000000000..7a8a18670ea5 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol @@ -0,0 +1,14 @@ +contract Test { + function set(uint24[3][4] memory x) public { + x[2][2] = 1; + x[3][2] = 7; + } + + function f() public returns (uint24[3][4] memory) { + uint24[3][4] memory data; + set(data); + return data; + } +} +// ---- +// f() -> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07 diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol b/test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol new file mode 100644 index 000000000000..c16705643f1a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol @@ -0,0 +1,69 @@ +contract Test { + struct S { + uint8 x; + uint16 y; + uint256 z; + } + struct X { + uint8 x; + S s; + uint8[2] a; + } + X m_x; + + function load() + public + returns ( + uint256 a, + uint256 x, + uint256 y, + uint256 z, + uint256 a1, + uint256 a2 + ) + { + m_x.x = 1; + m_x.s.x = 2; + m_x.s.y = 3; + m_x.s.z = 4; + m_x.a[0] = 5; + m_x.a[1] = 6; + X memory d = m_x; + a = d.x; + x = d.s.x; + y = d.s.y; + z = d.s.z; + a1 = d.a[0]; + a2 = d.a[1]; + } + + function store() + public + returns ( + uint256 a, + uint256 x, + uint256 y, + uint256 z, + uint256 a1, + uint256 a2 + ) + { + X memory d; + d.x = 1; + d.s.x = 2; + d.s.y = 3; + d.s.z = 4; + d.a[0] = 5; + d.a[1] = 6; + m_x = d; + a = m_x.x; + x = m_x.s.x; + y = m_x.s.y; + z = m_x.s.z; + a1 = m_x.a[0]; + a2 = m_x.a[1]; + } +} +// ---- +// load() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 +// store() -> 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 diff --git a/test/libsolidity/semanticTests/extracted/msg_sig.sol b/test/libsolidity/semanticTests/extracted/msg_sig.sol new file mode 100644 index 000000000000..11b9a5339e79 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/msg_sig.sol @@ -0,0 +1,9 @@ +contract test { + function foo(uint256 a) public returns (bytes4 value) { + return msg.sig; + } +} +// ==== +// compileViaYul: also +// ---- +// foo(uint256): 0x0 -> 0x2fbebd3800000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol b/test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol new file mode 100644 index 000000000000..646f8f6e91a6 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol @@ -0,0 +1,13 @@ +contract test { + function boo() public returns (bytes4 value) { + return msg.sig; + } + + function foo(uint256 a) public returns (bytes4 value) { + return boo(); + } +} +// ==== +// compileViaYul: also +// ---- +// foo(uint256): 0x0 -> 0x2fbebd3800000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/extracted/multi_modifiers.sol b/test/libsolidity/semanticTests/extracted/multi_modifiers.sol new file mode 100644 index 000000000000..07f6c038d3db --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/multi_modifiers.sol @@ -0,0 +1,23 @@ +// This triggered a bug in some version because the variable in the modifier was not +// unregistered correctly. +contract C { + uint256 public x; + modifier m1 { + address a1 = msg.sender; + x++; + _; + } + + function f1() public m1() { + x += 7; + } + + function f2() public m1() { + x += 3; + } +} +// ---- +// f1() -> +// x() -> 0x08 +// f2() -> +// x() -> 0x0c diff --git a/test/libsolidity/semanticTests/extracted/reusing_memory.sol b/test/libsolidity/semanticTests/extracted/reusing_memory.sol new file mode 100644 index 000000000000..b2876eeb335a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/reusing_memory.sol @@ -0,0 +1,26 @@ +// Invoke some features that use memory and test that they do not interfere with each other. +contract Helper { + uint256 public flag; + + constructor(uint256 x) public { + flag = x; + } +} + + +contract Main { + mapping(uint256 => uint256) map; + + function f(uint256 x) public returns (uint256) { + map[x] = x; + return + (new Helper(uint256(keccak256(abi.encodePacked(this.g(map[x])))))) + .flag(); + } + + function g(uint256 a) public returns (uint256) { + return map[a]; + } +} +// ---- +// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1 diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled.sol b/test/libsolidity/semanticTests/extracted/shift_right_garbled.sol new file mode 100644 index 000000000000..c0d6be8bd5b2 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_garbled.sol @@ -0,0 +1,14 @@ +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + assembly { + a := 0xffffffff + } + // Higher bits should be cleared before the shift + return a >> b; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(uint8,uint8): 0x00, 0x04 -> 0x0f +// f(uint8,uint8): 0x00, 0x1004 -> 0x0f diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol b/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol new file mode 100644 index 000000000000..df0570cb7536 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol @@ -0,0 +1,30 @@ +contract C { + function f(int8 a, uint8 b) public returns (int256) { + assembly { + a := 0xfffffff0 + } + // Higher bits should be signextended before the shift + return a >> b; + } + + function g(int8 a, uint8 b) public returns (int256) { + assembly { + a := 0xf0 + } + // Higher bits should be signextended before the shift + return a >> b; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// f(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// f(int8,uint8): 0x00, 0xff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// f(int8,uint8): 0x00, 0x1003 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// f(int8,uint8): 0x00, 0x1004 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// g(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// g(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// g(int8,uint8): 0x00, 0xff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// g(int8,uint8): 0x00, 0x1003 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// g(int8,uint8): 0x00, 0x1004 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol new file mode 100644 index 000000000000..0c1949a59dc3 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol @@ -0,0 +1,31 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(int8 a, uint8 b) public returns (int256) { + assembly { + a := 0xfffffff0 + } + // Higher bits should be signextended before the shift + return a >> b; + } + + function g(int8 a, uint8 b) public returns (int256) { + assembly { + a := 0xf0 + } + // Higher bits should be signextended before the shift + return a >> b; + } +} +// ---- +// f(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// f(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// f(int8,uint8): 0x00, 0xff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// f(int8,uint8): 0x00, 0x1003 -> FAILURE +// f(int8,uint8): 0x00, 0x1004 -> FAILURE +// g(int8,uint8): 0x00, 0x03 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe +// g(int8,uint8): 0x00, 0x04 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// g(int8,uint8): 0x00, 0xff -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +// g(int8,uint8): 0x00, 0x1003 -> FAILURE +// g(int8,uint8): 0x00, 0x1004 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol new file mode 100644 index 000000000000..54ac9540fc89 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol @@ -0,0 +1,15 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(uint8 a, uint8 b) public returns (uint256) { + assembly { + a := 0xffffffff + } + // Higher bits should be cleared before the shift + return a >> b; + } +} +// ---- +// f(uint8,uint8): 0x00, 0x04 -> 0x0f +// f(uint8,uint8): 0x00, 0x1004 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol new file mode 100644 index 000000000000..c59107f52f3d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol @@ -0,0 +1,13 @@ +contract C { + function f(int16 a, int16 b) public returns (int16) { + return a >> b; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(int16,int16): 0xff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +// f(int16,int16): 0xff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +// f(int16,int16): 0xff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6 +// f(int16,int16): 0xff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9 +// f(int16,int16): 0xff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol new file mode 100644 index 000000000000..6e462e704494 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(int16 a, int16 b) public returns (int16) { + return a >> b; + } +} +// ---- +// f(int16,int16): 0xff99, 0x00 -> FAILURE +// f(int16,int16): 0xff99, 0x01 -> FAILURE +// f(int16,int16): 0xff99, 0x02 -> FAILURE +// f(int16,int16): 0xff99, 0x04 -> FAILURE +// f(int16,int16): 0xff99, 0x08 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol new file mode 100644 index 000000000000..74e9d53b0ddf --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol @@ -0,0 +1,13 @@ +contract C { + function f(int32 a, int32 b) public returns (int32) { + return a >> b; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(int32,int32): 0xffffff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +// f(int32,int32): 0xffffff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +// f(int32,int32): 0xffffff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6 +// f(int32,int32): 0xffffff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9 +// f(int32,int32): 0xffffff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol new file mode 100644 index 000000000000..2466298f02ea --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(int32 a, int32 b) public returns (int32) { + return a >> b; + } +} +// ---- +// f(int32,int32): 0xffffff99, 0x00 -> FAILURE +// f(int32,int32): 0xffffff99, 0x01 -> FAILURE +// f(int32,int32): 0xffffff99, 0x02 -> FAILURE +// f(int32,int32): 0xffffff99, 0x04 -> FAILURE +// f(int32,int32): 0xffffff99, 0x08 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol new file mode 100644 index 000000000000..06dcf8eb5be0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol @@ -0,0 +1,13 @@ +contract C { + function f(int8 a, int8 b) public returns (int8) { + return a >> b; + } +} +// ==== +// ABIEncoderV1Only: true +// ---- +// f(int8,int8): 0x99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99 +// f(int8,int8): 0x99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc +// f(int8,int8): 0x99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6 +// f(int8,int8): 0x99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9 +// f(int8,int8): 0x99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol new file mode 100644 index 000000000000..643bc5e62b77 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol @@ -0,0 +1,14 @@ +pragma experimental ABIEncoderV2; + + +contract C { + function f(int8 a, int8 b) public returns (int8) { + return a >> b; + } +} +// ---- +// f(int8,int8): 0x99, 0x00 -> FAILURE +// f(int8,int8): 0x99, 0x01 -> FAILURE +// f(int8,int8): 0x99, 0x02 -> FAILURE +// f(int8,int8): 0x99, 0x04 -> FAILURE +// f(int8,int8): 0x99, 0x08 -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol b/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol new file mode 100644 index 000000000000..96c5419bea6b --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol @@ -0,0 +1,39 @@ +contract C { + uint256 x; + + function f() public returns (uint256) { + x = 3; + return 1; + } +} + + +interface CView { + function f() external view returns (uint256); +} + + +interface CPure { + function f() external pure returns (uint256); +} + + +contract D { + function f() public returns (uint256) { + return (new C()).f(); + } + + function fview() public returns (uint256) { + return (CView(address(new C()))).f(); + } + + function fpure() public returns (uint256) { + return (CPure(address(new C()))).f(); + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// f() -> 0x1 # This should work, next should throw # +// fview() -> FAILURE +// fpure() -> FAILURE diff --git a/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol b/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol new file mode 100644 index 000000000000..a193e875204d --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol @@ -0,0 +1,39 @@ +contract C { + uint256 x; + + function f() public returns (uint256) { + x = 3; + return 1; + } +} + + +interface CView { + function f() external view returns (uint256); +} + + +interface CPure { + function f() external pure returns (uint256); +} + + +contract D { + function f() public returns (uint256) { + return (new C()).f(); + } + + function fview() public returns (uint256) { + return (CView(address(new C()))).f(); + } + + function fpure() public returns (uint256) { + return (CPure(address(new C()))).f(); + } +} +// ==== +// EVMVersion: 0x1 +// fview() -> 1 +// fpure() -> 1 diff --git a/test/libsolidity/semanticTests/extracted/string_allocation_bug.sol b/test/libsolidity/semanticTests/extracted/string_allocation_bug.sol new file mode 100644 index 000000000000..9c2ec2e5352a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/string_allocation_bug.sol @@ -0,0 +1,20 @@ +contract Sample { + struct s { + uint16 x; + uint16 y; + string a; + string b; + } + s[2] public p; + + constructor() public { + s memory m; + m.x = 0xbbbb; + m.y = 0xcccc; + m.a = "hello"; + m.b = "world"; + p[0] = m; + } +} +// ---- +// p(uint256): 0x0 -> 0xbbbb, 0xcccc, 0x80, 0xc0, 0x05, "hello", 0x05, "world" diff --git a/test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol b/test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol new file mode 100644 index 000000000000..9578fc4f758a --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol @@ -0,0 +1,17 @@ +contract Test { + string s; + bytes b; + + function f(string memory _s, uint256 n) public returns (bytes1) { + b = bytes(_s); + s = string(b); + return bytes(s)[n]; + } + + function l() public returns (uint256) { + return bytes(s).length; + } +} +// ---- +// f(string,uint256): 0x40, 0x02, 0x06, "abcdef" -> "c" +// l() -> 0x06 diff --git a/test/libsolidity/semanticTests/extracted/strings_in_struct.sol b/test/libsolidity/semanticTests/extracted/strings_in_struct.sol new file mode 100644 index 000000000000..a6ec607f442e --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/strings_in_struct.sol @@ -0,0 +1,35 @@ +contract buggystruct { + Buggy public bug; + + struct Buggy { + uint256 first; + uint256 second; + uint256 third; + string last; + } + + constructor() public { + bug = Buggy(10, 20, 30, "asdfghjkl"); + } + + function getFirst() public returns (uint256) { + return bug.first; + } + + function getSecond() public returns (uint256) { + return bug.second; + } + + function getThird() public returns (uint256) { + return bug.third; + } + + function getLast() public returns (string memory) { + return bug.last; + } +} +// ---- +// getFirst() -> 0x0a +// getSecond() -> 0x14 +// getThird() -> 0x1e +// getLast() -> 0x20, 0x09, "asdfghjkl" diff --git a/test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol b/test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol new file mode 100644 index 000000000000..dbd67ab586c0 --- /dev/null +++ b/test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol @@ -0,0 +1,30 @@ +contract C { + struct X { + uint256 x1; + uint256 x2; + } + struct S { + uint256 s1; + uint256[3] s2; + X s3; + } + S s; + + constructor() public { + uint256[3] memory s2; + s2[1] = 9; + s = S(1, s2, X(4, 5)); + } + + function get() + public + returns (uint256 s1, uint256[3] memory s2, uint256 x1, uint256 x2) + { + s1 = s.s1; + s2 = s.s2; + x1 = s.s3.x1; + x2 = s.s3.x2; + } +} +// ---- +// get() -> 0x01, 0x00, 0x09, 0x00, 0x04, 0x05 From 165f7bf60f50a0ad8799591331c6e3363da17aa3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 26 Mar 2020 17:47:36 +0100 Subject: [PATCH 128/165] Move files. --- .../{extracted => abiencodedecode}/abi_decode_calldata.sol | 0 .../{extracted => abiencodedecode}/abi_decode_simple.sol | 0 .../{extracted => abiencodedecode}/abi_decode_simple_storage.sol | 0 .../{extracted => abiencodedecode}/abi_encode_empty_string.sol | 0 .../{extracted => array}/arrays_complex_from_and_to_storage.sol | 0 .../{extracted => array}/arrays_complex_memory_index_access.sol | 0 .../{extracted => array}/bytes_memory_index_access.sol | 0 .../{extracted => array}/fixed_arrays_in_storage.sol | 0 .../{extracted => array}/fixed_bytes_index_access.sol | 0 .../memory_arrays_dynamic_index_access_write.sol | 0 .../{extracted => array}/memory_arrays_index_access_write.sol | 0 .../semanticTests/{extracted => array}/reusing_memory.sol | 0 .../semanticTests/{extracted => array}/string_allocation_bug.sol | 0 .../{extracted => array}/string_bytes_conversion.sol | 0 .../semanticTests/{extracted => array}/strings_in_struct.sol | 0 .../assignment_to_const_var_involving_keccak.sol | 0 .../{extracted => builtinFunctions}/function_types_sig.sol | 0 .../iterated_keccak256_with_bytes.sol | 0 .../keccak256_multiple_arguments.sol | 0 .../keccak256_multiple_arguments_with_numeric_literals.sol | 0 .../keccak256_multiple_arguments_with_string_literals.sol | 0 .../semanticTests/{extracted => builtinFunctions}/msg_sig.sol | 0 .../msg_sig_after_internal_call_is_same.sol | 0 .../{extracted => calldata}/calldata_array_dynamic_bytes.sol | 0 .../{extracted => calldata}/calldata_bytes_array_to_memory.sol | 0 .../{extracted => calldata}/calldata_string_array.sol | 0 .../{extracted => calldata}/calldata_struct_cleaning.sol | 0 .../semanticTests/{extracted => cleanup}/bool_conversion.sol | 0 .../semanticTests/{extracted => cleanup}/bool_conversion_v2.sol | 0 .../{extracted => cleanup}/cleanup_address_types.sol | 0 .../{extracted => cleanup}/cleanup_address_types_v2.sol | 0 .../semanticTests/{extracted => cleanup}/cleanup_bytes_types.sol | 0 .../{extracted => cleanup}/cleanup_bytes_types_v2.sol | 0 .../{extracted => functionCall}/delegatecall_return_value.sol | 0 .../delegatecall_return_value_pre_byzantium.sol | 0 .../{extracted => shifts}/bitwise_shifting_constantinople.sol | 0 .../bitwise_shifting_constantinople_combined.sol | 0 .../bitwise_shifting_constants_constantinople.sol | 0 .../semanticTests/{extracted => shifts}/shift_right_garbled.sol | 0 .../{extracted => shifts}/shift_right_garbled_signed.sol | 0 .../{extracted => shifts}/shift_right_garbled_signed_v2.sol | 0 .../{extracted => shifts}/shift_right_garbled_v2.sol | 0 .../shift_right_negative_lvalue_signextend_int16.sol | 0 .../shift_right_negative_lvalue_signextend_int16_v2.sol | 0 .../shift_right_negative_lvalue_signextend_int32.sol | 0 .../shift_right_negative_lvalue_signextend_int32_v2.sol | 0 .../shift_right_negative_lvalue_signextend_int8.sol | 0 .../shift_right_negative_lvalue_signextend_int8_v2.sol | 0 .../{extracted => structs}/memory_structs_nested_load.sol | 0 .../{extracted => structs}/struct_constructor_nested.sol | 0 .../semanticTests/{extracted => various}/multi_modifiers.sol | 0 .../{extracted => various}/staticcall_for_view_and_pure.sol | 0 .../staticcall_for_view_and_pure_pre_byzantium.sol | 0 53 files changed, 0 insertions(+), 0 deletions(-) rename test/libsolidity/semanticTests/{extracted => abiencodedecode}/abi_decode_calldata.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiencodedecode}/abi_decode_simple.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiencodedecode}/abi_decode_simple_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => abiencodedecode}/abi_encode_empty_string.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/arrays_complex_from_and_to_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/arrays_complex_memory_index_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/bytes_memory_index_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_arrays_in_storage.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/fixed_bytes_index_access.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/memory_arrays_dynamic_index_access_write.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/memory_arrays_index_access_write.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/reusing_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/string_allocation_bug.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/string_bytes_conversion.sol (100%) rename test/libsolidity/semanticTests/{extracted => array}/strings_in_struct.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/assignment_to_const_var_involving_keccak.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/function_types_sig.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/iterated_keccak256_with_bytes.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/keccak256_multiple_arguments.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/keccak256_multiple_arguments_with_numeric_literals.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/keccak256_multiple_arguments_with_string_literals.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/msg_sig.sol (100%) rename test/libsolidity/semanticTests/{extracted => builtinFunctions}/msg_sig_after_internal_call_is_same.sol (100%) rename test/libsolidity/semanticTests/{extracted => calldata}/calldata_array_dynamic_bytes.sol (100%) rename test/libsolidity/semanticTests/{extracted => calldata}/calldata_bytes_array_to_memory.sol (100%) rename test/libsolidity/semanticTests/{extracted => calldata}/calldata_string_array.sol (100%) rename test/libsolidity/semanticTests/{extracted => calldata}/calldata_struct_cleaning.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/bool_conversion.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/bool_conversion_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_address_types.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_address_types_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_bytes_types.sol (100%) rename test/libsolidity/semanticTests/{extracted => cleanup}/cleanup_bytes_types_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/delegatecall_return_value.sol (100%) rename test/libsolidity/semanticTests/{extracted => functionCall}/delegatecall_return_value_pre_byzantium.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/bitwise_shifting_constantinople.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/bitwise_shifting_constantinople_combined.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/bitwise_shifting_constants_constantinople.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_garbled.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_garbled_signed.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_garbled_signed_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_garbled_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int16.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int16_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int32.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int32_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int8.sol (100%) rename test/libsolidity/semanticTests/{extracted => shifts}/shift_right_negative_lvalue_signextend_int8_v2.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/memory_structs_nested_load.sol (100%) rename test/libsolidity/semanticTests/{extracted => structs}/struct_constructor_nested.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/multi_modifiers.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/staticcall_for_view_and_pure.sol (100%) rename test/libsolidity/semanticTests/{extracted => various}/staticcall_for_view_and_pure_pre_byzantium.sol (100%) diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_calldata.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_calldata.sol rename to test/libsolidity/semanticTests/abiencodedecode/abi_decode_calldata.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_simple.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_simple.sol rename to test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_decode_simple_storage.sol rename to test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_encode_empty_string.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/abi_encode_empty_string.sol rename to test/libsolidity/semanticTests/abiencodedecode/abi_encode_empty_string.sol diff --git a/test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/arrays_complex_from_and_to_storage.sol rename to test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol b/test/libsolidity/semanticTests/array/arrays_complex_memory_index_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/arrays_complex_memory_index_access.sol rename to test/libsolidity/semanticTests/array/arrays_complex_memory_index_access.sol diff --git a/test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol b/test/libsolidity/semanticTests/array/bytes_memory_index_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bytes_memory_index_access.sol rename to test/libsolidity/semanticTests/array/bytes_memory_index_access.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol b/test/libsolidity/semanticTests/array/fixed_arrays_in_storage.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_arrays_in_storage.sol rename to test/libsolidity/semanticTests/array/fixed_arrays_in_storage.sol diff --git a/test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol b/test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/fixed_bytes_index_access.sol rename to test/libsolidity/semanticTests/array/fixed_bytes_index_access.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol b/test/libsolidity/semanticTests/array/memory_arrays_dynamic_index_access_write.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_arrays_dynamic_index_access_write.sol rename to test/libsolidity/semanticTests/array/memory_arrays_dynamic_index_access_write.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol b/test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_arrays_index_access_write.sol rename to test/libsolidity/semanticTests/array/memory_arrays_index_access_write.sol diff --git a/test/libsolidity/semanticTests/extracted/reusing_memory.sol b/test/libsolidity/semanticTests/array/reusing_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/reusing_memory.sol rename to test/libsolidity/semanticTests/array/reusing_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/string_allocation_bug.sol b/test/libsolidity/semanticTests/array/string_allocation_bug.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/string_allocation_bug.sol rename to test/libsolidity/semanticTests/array/string_allocation_bug.sol diff --git a/test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol b/test/libsolidity/semanticTests/array/string_bytes_conversion.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/string_bytes_conversion.sol rename to test/libsolidity/semanticTests/array/string_bytes_conversion.sol diff --git a/test/libsolidity/semanticTests/extracted/strings_in_struct.sol b/test/libsolidity/semanticTests/array/strings_in_struct.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/strings_in_struct.sol rename to test/libsolidity/semanticTests/array/strings_in_struct.sol diff --git a/test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol b/test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/assignment_to_const_var_involving_keccak.sol rename to test/libsolidity/semanticTests/builtinFunctions/assignment_to_const_var_involving_keccak.sol diff --git a/test/libsolidity/semanticTests/extracted/function_types_sig.sol b/test/libsolidity/semanticTests/builtinFunctions/function_types_sig.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/function_types_sig.sol rename to test/libsolidity/semanticTests/builtinFunctions/function_types_sig.sol diff --git a/test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol b/test/libsolidity/semanticTests/builtinFunctions/iterated_keccak256_with_bytes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/iterated_keccak256_with_bytes.sol rename to test/libsolidity/semanticTests/builtinFunctions/iterated_keccak256_with_bytes.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments.sol rename to test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_numeric_literals.sol rename to test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_numeric_literals.sol diff --git a/test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol b/test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/keccak256_multiple_arguments_with_string_literals.sol rename to test/libsolidity/semanticTests/builtinFunctions/keccak256_multiple_arguments_with_string_literals.sol diff --git a/test/libsolidity/semanticTests/extracted/msg_sig.sol b/test/libsolidity/semanticTests/builtinFunctions/msg_sig.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/msg_sig.sol rename to test/libsolidity/semanticTests/builtinFunctions/msg_sig.sol diff --git a/test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol b/test/libsolidity/semanticTests/builtinFunctions/msg_sig_after_internal_call_is_same.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/msg_sig_after_internal_call_is_same.sol rename to test/libsolidity/semanticTests/builtinFunctions/msg_sig_after_internal_call_is_same.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol b/test/libsolidity/semanticTests/calldata/calldata_array_dynamic_bytes.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_array_dynamic_bytes.sol rename to test/libsolidity/semanticTests/calldata/calldata_array_dynamic_bytes.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol b/test/libsolidity/semanticTests/calldata/calldata_bytes_array_to_memory.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_bytes_array_to_memory.sol rename to test/libsolidity/semanticTests/calldata/calldata_bytes_array_to_memory.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_string_array.sol b/test/libsolidity/semanticTests/calldata/calldata_string_array.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_string_array.sol rename to test/libsolidity/semanticTests/calldata/calldata_string_array.sol diff --git a/test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol b/test/libsolidity/semanticTests/calldata/calldata_struct_cleaning.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/calldata_struct_cleaning.sol rename to test/libsolidity/semanticTests/calldata/calldata_struct_cleaning.sol diff --git a/test/libsolidity/semanticTests/extracted/bool_conversion.sol b/test/libsolidity/semanticTests/cleanup/bool_conversion.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bool_conversion.sol rename to test/libsolidity/semanticTests/cleanup/bool_conversion.sol diff --git a/test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol b/test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bool_conversion_v2.sol rename to test/libsolidity/semanticTests/cleanup/bool_conversion_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_address_types.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_address_types.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_address_types_v2.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_address_types_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_bytes_types.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_bytes_types.sol diff --git a/test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol b/test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/cleanup_bytes_types_v2.sol rename to test/libsolidity/semanticTests/cleanup/cleanup_bytes_types_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/delegatecall_return_value.sol rename to test/libsolidity/semanticTests/functionCall/delegatecall_return_value.sol diff --git a/test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol b/test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/delegatecall_return_value_pre_byzantium.sol rename to test/libsolidity/semanticTests/functionCall/delegatecall_return_value_pre_byzantium.sol diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol b/test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople.sol rename to test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople.sol diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol b/test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople_combined.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bitwise_shifting_constantinople_combined.sol rename to test/libsolidity/semanticTests/shifts/bitwise_shifting_constantinople_combined.sol diff --git a/test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol b/test/libsolidity/semanticTests/shifts/bitwise_shifting_constants_constantinople.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/bitwise_shifting_constants_constantinople.sol rename to test/libsolidity/semanticTests/shifts/bitwise_shifting_constants_constantinople.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_garbled.sol rename to test/libsolidity/semanticTests/shifts/shift_right_garbled.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_garbled_signed.sol rename to test/libsolidity/semanticTests/shifts/shift_right_garbled_signed.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_garbled_signed_v2.sol rename to test/libsolidity/semanticTests/shifts/shift_right_garbled_signed_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_garbled_v2.sol rename to test/libsolidity/semanticTests/shifts/shift_right_garbled_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int16_v2.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int16_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int32_v2.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int32_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8.sol diff --git a/test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol b/test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/shift_right_negative_lvalue_signextend_int8_v2.sol rename to test/libsolidity/semanticTests/shifts/shift_right_negative_lvalue_signextend_int8_v2.sol diff --git a/test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol b/test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/memory_structs_nested_load.sol rename to test/libsolidity/semanticTests/structs/memory_structs_nested_load.sol diff --git a/test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol b/test/libsolidity/semanticTests/structs/struct_constructor_nested.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/struct_constructor_nested.sol rename to test/libsolidity/semanticTests/structs/struct_constructor_nested.sol diff --git a/test/libsolidity/semanticTests/extracted/multi_modifiers.sol b/test/libsolidity/semanticTests/various/multi_modifiers.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/multi_modifiers.sol rename to test/libsolidity/semanticTests/various/multi_modifiers.sol diff --git a/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure.sol rename to test/libsolidity/semanticTests/various/staticcall_for_view_and_pure.sol diff --git a/test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol b/test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol similarity index 100% rename from test/libsolidity/semanticTests/extracted/staticcall_for_view_and_pure_pre_byzantium.sol rename to test/libsolidity/semanticTests/various/staticcall_for_view_and_pure_pre_byzantium.sol From 173f2348600a04c544c02d4a2b8f93946d2cc7b4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 24 Mar 2020 18:25:59 +0100 Subject: [PATCH 129/165] Refactor: Replace inheritance hierarchy by most derived contract. --- libsolidity/ast/AST.cpp | 58 ++++++++++++ libsolidity/ast/AST.h | 32 +++++++ libsolidity/codegen/CompilerContext.cpp | 93 +++++++------------ libsolidity/codegen/CompilerContext.h | 22 ++--- libsolidity/codegen/ContractCompiler.cpp | 9 +- libsolidity/codegen/ExpressionCompiler.cpp | 7 +- .../codegen/ir/IRGenerationContext.cpp | 27 ++---- libsolidity/codegen/ir/IRGenerationContext.h | 10 +- libsolidity/codegen/ir/IRGenerator.cpp | 4 +- .../codegen/ir/IRGeneratorForStatements.cpp | 2 +- .../SolidityExpressionCompiler.cpp | 6 +- 11 files changed, 156 insertions(+), 114 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index a76e6e274171..b711758d68c7 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -319,6 +319,37 @@ FunctionDefinitionAnnotation& FunctionDefinition::annotation() const return initAnnotation(); } +FunctionDefinition const& FunctionDefinition::resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart +) const +{ + solAssert(!isConstructor(), ""); + // If we are not doing super-lookup and the function is not virtual, we can stop here. + if (_searchStart == nullptr && !virtualSemantics()) + return *this; + + solAssert(!dynamic_cast(*scope()).isLibrary(), ""); + + FunctionType const* functionType = TypeProvider::function(*this)->asCallableFunction(false); + + for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts) + { + if (_searchStart != nullptr && c != _searchStart) + continue; + _searchStart = nullptr; + for (FunctionDefinition const* function: c->definedFunctions()) + if ( + function->name() == name() && + !function->isConstructor() && + FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(*functionType) + ) + return *function; + } + solAssert(false, "Virtual function " + name() + " not found."); + return *this; // not reached +} + TypePointer ModifierDefinition::type() const { return TypeProvider::modifier(*this); @@ -329,6 +360,33 @@ ModifierDefinitionAnnotation& ModifierDefinition::annotation() const return initAnnotation(); } +ModifierDefinition const& ModifierDefinition::resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart +) const +{ + solAssert(_searchStart == nullptr, "Used super in connection with modifiers."); + + // If we are not doing super-lookup and the modifier is not virtual, we can stop here. + if (_searchStart == nullptr && !virtualSemantics()) + return *this; + + solAssert(!dynamic_cast(*scope()).isLibrary(), ""); + + for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts) + { + if (_searchStart != nullptr && c != _searchStart) + continue; + _searchStart = nullptr; + for (ModifierDefinition const* modifier: c->functionModifiers()) + if (modifier->name() == name()) + return *modifier; + } + solAssert(false, "Virtual modifier " + name() + " not found."); + return *this; // not reached +} + + TypePointer EventDefinition::type() const { return TypeProvider::function(*this); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 052970bc862b..4bbacbdf3b90 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -689,6 +689,18 @@ class CallableDeclaration: public Declaration, public VariableScope CallableDeclarationAnnotation& annotation() const override = 0; + /// Performs virtual or super function/modifier lookup: + /// If @a _searchStart is nullptr, performs virtual function lookup, i.e. + /// searches the inheritance hierarchy of @a _mostDerivedContract towards the base + /// and returns the first function/modifier definition that + /// is overwritten by this callable. + /// If @a _searchStart is non-null, starts searching only from that contract, but + /// still in the hierarchy of @a _mostDerivedContract. + virtual CallableDeclaration const& resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart = nullptr + ) const = 0; + protected: ASTPointer m_parameters; ASTPointer m_overrides; @@ -799,6 +811,12 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen CallableDeclaration::virtualSemantics() || (annotation().contract && annotation().contract->isInterface()); } + + FunctionDefinition const& resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart = nullptr + ) const override; + private: StateMutability m_stateMutability; Token const m_kind; @@ -945,6 +963,12 @@ class ModifierDefinition: public CallableDeclaration, public StructurallyDocumen ModifierDefinitionAnnotation& annotation() const override; + ModifierDefinition const& resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart = nullptr + ) const override; + + private: ASTPointer m_body; }; @@ -1010,6 +1034,14 @@ class EventDefinition: public CallableDeclaration, public StructurallyDocumented EventDefinitionAnnotation& annotation() const override; + CallableDeclaration const& resolveVirtual( + ContractDefinition const&, + ContractDefinition const* + ) const override + { + solAssert(false, "Tried to resolve virtual event."); + } + private: bool m_anonymous = false; }; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 26cff59eccba..6984a030ba60 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -272,55 +272,41 @@ evmasm::AssemblyItem CompilerContext::functionEntryLabelIfExists(Declaration con return m_functionCompilationQueue.entryLabelIfExists(_declaration); } -FunctionDefinition const& CompilerContext::resolveVirtualFunction(FunctionDefinition const& _function) -{ - // Libraries do not allow inheritance and their functions can be inlined, so we should not - // search the inheritance hierarchy (which will be the wrong one in case the function - // is inlined). - if (auto scope = dynamic_cast(_function.scope())) - if (scope->isLibrary()) - return _function; - solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - return resolveVirtualFunction(_function, m_inheritanceHierarchy.begin()); -} - FunctionDefinition const& CompilerContext::superFunction(FunctionDefinition const& _function, ContractDefinition const& _base) { - solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - return resolveVirtualFunction(_function, superContract(_base)); + solAssert(m_mostDerivedContract, "No most derived contract set."); + ContractDefinition const* super = superContract(_base); + solAssert(super, "Super contract not available."); + return _function.resolveVirtual(mostDerivedContract(), super); } FunctionDefinition const* CompilerContext::nextConstructor(ContractDefinition const& _contract) const { - vector::const_iterator it = superContract(_contract); - for (; it != m_inheritanceHierarchy.end(); ++it) - if ((*it)->constructor()) - return (*it)->constructor(); + ContractDefinition const* next = superContract(_contract); + if (next == nullptr) + return nullptr; + for (ContractDefinition const* c: m_mostDerivedContract->annotation().linearizedBaseContracts) + if (next != nullptr && next != c) + continue; + else + { + next = nullptr; + if (c->constructor()) + return c->constructor(); + } return nullptr; } -Declaration const* CompilerContext::nextFunctionToCompile() const +ContractDefinition const& CompilerContext::mostDerivedContract() const { - return m_functionCompilationQueue.nextFunctionToCompile(); + solAssert(m_mostDerivedContract, "Most derived contract not set."); + return *m_mostDerivedContract; } -ModifierDefinition const& CompilerContext::resolveVirtualFunctionModifier( - ModifierDefinition const& _modifier -) const +Declaration const* CompilerContext::nextFunctionToCompile() const { - // Libraries do not allow inheritance and their functions can be inlined, so we should not - // search the inheritance hierarchy (which will be the wrong one in case the function - // is inlined). - if (auto scope = dynamic_cast(_modifier.scope())) - if (scope->isLibrary()) - return _modifier; - solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - for (ContractDefinition const* contract: m_inheritanceHierarchy) - for (ModifierDefinition const* modifier: contract->functionModifiers()) - if (modifier->name() == _modifier.name()) - return *modifier; - solAssert(false, "Function modifier " + _modifier.name() + " not found in inheritance hierarchy."); + return m_functionCompilationQueue.nextFunctionToCompile(); } unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const @@ -556,32 +542,19 @@ LinkerObject const& CompilerContext::assembledObject() const return object; } -FunctionDefinition const& CompilerContext::resolveVirtualFunction( - FunctionDefinition const& _function, - vector::const_iterator _searchStart -) +ContractDefinition const* CompilerContext::superContract(ContractDefinition const& _contract) const { - string name = _function.name(); - FunctionType functionType(_function); - auto it = _searchStart; - for (; it != m_inheritanceHierarchy.end(); ++it) - for (FunctionDefinition const* function: (*it)->definedFunctions()) - if ( - function->name() == name && - !function->isConstructor() && - FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(functionType) - ) - return *function; - solAssert(false, "Super function " + name + " not found."); - return _function; // not reached -} - -vector::const_iterator CompilerContext::superContract(ContractDefinition const& _contract) const -{ - solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_contract); - solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy."); - return ++it; + auto const& hierarchy = mostDerivedContract().annotation().linearizedBaseContracts; + auto it = find(hierarchy.begin(), hierarchy.end(), &_contract); + solAssert(it != hierarchy.end(), "Base not found in inheritance hierarchy."); + ++it; + if (it == hierarchy.end()) + return nullptr; + else + { + solAssert(*it != &_contract, ""); + return *it; + } } string CompilerContext::revertReasonIfDebug(string const& _message) diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index ec846af83101..a8e494435321 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -114,15 +114,14 @@ class CompilerContext /// @returns the entry label of the given function. Might return an AssemblyItem of type /// UndefinedItem if it does not exist yet. evmasm::AssemblyItem functionEntryLabelIfExists(Declaration const& _declaration) const; - /// @returns the entry label of the given function and takes overrides into account. - FunctionDefinition const& resolveVirtualFunction(FunctionDefinition const& _function); /// @returns the function that overrides the given declaration from the most derived class just /// above _base in the current inheritance hierarchy. FunctionDefinition const& superFunction(FunctionDefinition const& _function, ContractDefinition const& _base); /// @returns the next constructor in the inheritance hierarchy. FunctionDefinition const* nextConstructor(ContractDefinition const& _contract) const; - /// Sets the current inheritance hierarchy from derived to base. - void setInheritanceHierarchy(std::vector const& _hierarchy) { m_inheritanceHierarchy = _hierarchy; } + /// Sets the contract currently being compiled - the most derived one. + void setMostDerivedContract(ContractDefinition const& _contract) { m_mostDerivedContract = &_contract; } + ContractDefinition const& mostDerivedContract() const; /// @returns the next function in the queue of functions that are still to be compiled /// (i.e. that were referenced during compilation but where we did not yet generate code for). @@ -171,7 +170,6 @@ class CompilerContext /// empty return value. std::pair> requestedYulFunctions(); - ModifierDefinition const& resolveVirtualFunctionModifier(ModifierDefinition const& _modifier) const; /// Returns the distance of the given local variable from the bottom of the stack (of the current function). unsigned baseStackOffsetOfVariable(Declaration const& _declaration) const; /// If supplied by a value returned by @ref baseStackOffsetOfVariable(variable), returns @@ -315,14 +313,8 @@ class CompilerContext RevertStrings revertStrings() const { return m_revertStrings; } private: - /// Searches the inheritance hierarchy towards the base starting from @a _searchStart and returns - /// the first function definition that is overwritten by _function. - FunctionDefinition const& resolveVirtualFunction( - FunctionDefinition const& _function, - std::vector::const_iterator _searchStart - ); - /// @returns an iterator to the contract directly above the given contract. - std::vector::const_iterator superContract(ContractDefinition const& _contract) const; + /// @returns a pointer to the contract directly above the given contract. + ContractDefinition const* superContract(ContractDefinition const& _contract) const; /// Updates source location set in the assembly. void updateSourceLocation(); @@ -381,8 +373,8 @@ class CompilerContext /// modifier is applied twice, the position of the variable needs to be restored /// after the nested modifier is left. std::map> m_localVariables; - /// List of current inheritance hierarchy from derived to base. - std::vector m_inheritanceHierarchy; + /// The contract currently being compiled. Virtual function lookup starts from this contarct. + ContractDefinition const* m_mostDerivedContract = nullptr; /// Stack of current visited AST nodes, used for location attachment std::stack m_visitedNodes; /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index d5f5ffe3308f..50fb030d238f 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -129,7 +129,7 @@ void ContractCompiler::initializeContext( { m_context.setExperimentalFeatures(_contract.sourceUnit().annotation().experimentalFeatures); m_context.setOtherCompilers(_otherCompilers); - m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts); + m_context.setMostDerivedContract(_contract); if (m_runtimeCompiler) registerImmutableVariables(_contract); CompilerUtils(m_context).initialiseFreeMemoryPointer(); @@ -689,7 +689,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) if (FunctionDefinition const* functionDef = dynamic_cast(decl)) { solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); - functionDef = &m_context.resolveVirtualFunction(*functionDef); + functionDef = &functionDef->resolveVirtual(m_context.mostDerivedContract()); auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); solAssert(functionEntryLabel.data() <= std::numeric_limits::max(), ""); _assembly.appendLabelReference(size_t(functionEntryLabel.data())); @@ -1335,10 +1335,9 @@ void ContractCompiler::appendModifierOrFunctionCode() appendModifierOrFunctionCode(); else { - ModifierDefinition const& nonVirtualModifier = dynamic_cast( + ModifierDefinition const& modifier = dynamic_cast( *modifierInvocation->name()->annotation().referencedDeclaration - ); - ModifierDefinition const& modifier = m_context.resolveVirtualFunctionModifier(nonVirtualModifier); + ).resolveVirtual(m_context.mostDerivedContract()); CompilerContext::LocationSetter locationSetter(m_context, modifier); std::vector> const& modifierArguments = modifierInvocation->arguments() ? *modifierInvocation->arguments() : std::vector>(); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index c71d067c4ae8..58992426be37 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -572,7 +572,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // Do not directly visit the identifier, because this way, we can avoid // the runtime entry label to be created at the creation time context. CompilerContext::LocationSetter locationSetter2(m_context, *identifier); - utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef), false); + utils().pushCombinedFunctionEntryLabel( + functionDef->resolveVirtual(m_context.mostDerivedContract()), + false + ); shortcutTaken = true; } } @@ -1861,7 +1864,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) // we want to avoid having a reference to the runtime function entry point in the // constructor context, since this would force the compiler to include unreferenced // internal functions in the runtime contex. - utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef)); + utils().pushCombinedFunctionEntryLabel(functionDef->resolveVirtual(m_context.mostDerivedContract())); else if (auto variable = dynamic_cast(declaration)) appendVariable(*variable, static_cast(_identifier)); else if (auto contract = dynamic_cast(declaration)) diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 7184247f4014..288da5937992 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -31,6 +31,12 @@ using namespace solidity; using namespace solidity::util; using namespace solidity::frontend; +ContractDefinition const& IRGenerationContext::mostDerivedContract() const +{ + solAssert(m_mostDerivedContract, "Most derived contract requested but not set."); + return *m_mostDerivedContract; +} + IRVariable const& IRGenerationContext::addLocalVariable(VariableDeclaration const& _varDecl) { auto const& [it, didInsert] = m_localVariables.emplace( @@ -70,26 +76,9 @@ string IRGenerationContext::functionName(VariableDeclaration const& _varDecl) return "getter_fun_" + _varDecl.name() + "_" + to_string(_varDecl.id()); } -FunctionDefinition const& IRGenerationContext::virtualFunction(FunctionDefinition const& _function) -{ - // @TODO previously, we had to distinguish creation context and runtime context, - // but since we do not work with jump positions anymore, this should not be a problem, right? - string name = _function.name(); - FunctionType functionType(_function); - for (auto const& contract: m_inheritanceHierarchy) - for (FunctionDefinition const* function: contract->definedFunctions()) - if ( - function->name() == name && - !function->isConstructor() && - FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(functionType) - ) - return *function; - solAssert(false, "Super function " + name + " not found."); -} - string IRGenerationContext::virtualFunctionName(FunctionDefinition const& _functionDeclaration) { - return functionName(virtualFunction(_functionDeclaration)); + return functionName(_functionDeclaration.resolveVirtual(mostDerivedContract())); } string IRGenerationContext::newYulVariable() @@ -120,7 +109,7 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out) templ("arrow", _out > 0 ? "->" : ""); templ("out", suffixedVariableNameList("out_", 0, _out)); vector> functions; - for (auto const& contract: m_inheritanceHierarchy) + for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) for (FunctionDefinition const* function: contract->definedFunctions()) if ( !function->isConstructor() && diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 473b62482d4a..b0fc92cdb8c3 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -61,11 +61,12 @@ class IRGenerationContext MultiUseYulFunctionCollector& functionCollector() { return m_functions; } - /// Sets the current inheritance hierarchy from derived to base. - void setInheritanceHierarchy(std::vector _hierarchy) + /// Sets the most derived contract (the one currently being compiled)> + void setMostDerivedContract(ContractDefinition const& _mostDerivedContract) { - m_inheritanceHierarchy = std::move(_hierarchy); + m_mostDerivedContract = &_mostDerivedContract; } + ContractDefinition const& mostDerivedContract() const; IRVariable const& addLocalVariable(VariableDeclaration const& _varDecl); @@ -81,7 +82,6 @@ class IRGenerationContext std::string functionName(FunctionDefinition const& _function); std::string functionName(VariableDeclaration const& _varDecl); - FunctionDefinition const& virtualFunction(FunctionDefinition const& _functionDeclaration); std::string virtualFunctionName(FunctionDefinition const& _functionDeclaration); std::string newYulVariable(); @@ -103,7 +103,7 @@ class IRGenerationContext langutil::EVMVersion m_evmVersion; RevertStrings m_revertStrings; OptimiserSettings m_optimiserSettings; - std::vector m_inheritanceHierarchy; + ContractDefinition const* m_mostDerivedContract = nullptr; std::map m_localVariables; /// Storage offsets of state variables std::map> m_stateVariables; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 9c7d9c8ace74..4ca00befbf37 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -110,7 +110,7 @@ string IRGenerator::generate(ContractDefinition const& _contract) t("functions", m_context.functionCollector().requestedFunctions()); resetContext(_contract); - m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts); + m_context.setMostDerivedContract(_contract); t("RuntimeObject", runtimeObjectName(_contract)); t("dispatch", dispatchRoutine(_contract)); for (auto const* contract: _contract.annotation().linearizedBaseContracts) @@ -389,7 +389,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract) ); m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings); - m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts); + m_context.setMostDerivedContract(_contract); for (auto const& var: ContractType(_contract).stateVariables()) m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var)); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1d40c35b1970..b5d9589c0348 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1165,7 +1165,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) return; } else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) - define(_identifier) << to_string(m_context.virtualFunction(*functionDef).id()) << "\n"; + define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n"; else if (VariableDeclaration const* varDecl = dynamic_cast(declaration)) { // TODO for the constant case, we have to be careful: diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index cb0066bee2ab..cdaee104b128 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -119,13 +119,9 @@ bytes compileFirstExpression( NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), scopes, errorReporter); resolver.registerDeclarations(*sourceUnit); - vector inheritanceHierarchy; for (ASTPointer const& node: sourceUnit->nodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) - { BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*contract), "Resolving names failed"); - inheritanceHierarchy = vector(1, contract); - } for (ASTPointer const& node: sourceUnit->nodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) { @@ -144,7 +140,7 @@ bytes compileFirstExpression( RevertStrings::Default ); context.resetVisitedNodes(contract); - context.setInheritanceHierarchy(inheritanceHierarchy); + context.setMostDerivedContract(*contract); unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack context.adjustStackOffset(parametersSize); for (vector const& variable: _localVariables) From c184844932a468b5d7b3ce1a2d2351c11fc74aea Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Thu, 26 Mar 2020 18:57:43 -0400 Subject: [PATCH 130/165] Remove forward declaration of class Population --- tools/yulPhaser/Population.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/yulPhaser/Population.h b/tools/yulPhaser/Population.h index 1514741713f8..40d51498b181 100644 --- a/tools/yulPhaser/Population.h +++ b/tools/yulPhaser/Population.h @@ -29,13 +29,6 @@ namespace solidity::phaser { -class Population; - -} - -namespace solidity::phaser -{ - class PairSelection; class Selection; From 89d5ecdd24973692fc25a74854a0bc21dff2581d Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Mon, 23 Mar 2020 16:04:36 +0100 Subject: [PATCH 131/165] [Sol2Yul] Adding support for constructor with parameters --- libsolidity/codegen/ir/IRGenerator.cpp | 23 ++++++++++++++++--- .../semanticTests/constructor_with_params.sol | 15 ++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 test/libsolidity/semanticTests/constructor_with_params.sol diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 4ca00befbf37..2aff9c3f865a 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -259,11 +259,28 @@ string IRGenerator::constructorCode(ContractDefinition const& _contract) if (constructor) { - solUnimplementedAssert(constructor->parameters().empty(), ""); + ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); + unsigned paramVars = make_shared(constructor->functionType(false)->parameterTypes())->sizeOnStack(); + + Whiskers t(R"X( + let programSize := datasize("") + let argSize := sub(codesize(), programSize) + + let memoryDataOffset := (argSize) + codecopy(memoryDataOffset, programSize, argSize) + + (memoryDataOffset, add(memoryDataOffset, argSize)) - // TODO base constructors + () + )X"); + t("object", creationObjectName(_contract)); + t("allocate", m_utils.allocationFunction()); + t("assignToParams", paramVars == 0 ? "" : "let " + suffixedVariableNameList("param_", 0, paramVars) + " := "); + t("params", suffixedVariableNameList("param_", 0, paramVars)); + t("abiDecode", abiFunctions.tupleDecoder(constructor->functionType(false)->parameterTypes(), true)); + t("constructorName", m_context.functionName(*constructor)); - out << m_context.functionName(*constructor) + "()\n"; + out << t.render(); } return out.str(); diff --git a/test/libsolidity/semanticTests/constructor_with_params.sol b/test/libsolidity/semanticTests/constructor_with_params.sol new file mode 100644 index 000000000000..19f0bdb574c4 --- /dev/null +++ b/test/libsolidity/semanticTests/constructor_with_params.sol @@ -0,0 +1,15 @@ +contract C { + uint public i; + uint public k; + + constructor(uint newI, uint newK) public { + i = newI; + k = newK; + } +} +// ==== +// compileViaYul: also +// ---- +// constructor(): 2, 0 -> +// i() -> 2 +// k() -> 0 From 9cc967eb3ab3bad029fcbcf0da0f1f61d0d81525 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 30 Mar 2020 11:35:34 +0200 Subject: [PATCH 132/165] Removing grammar.txt in favor of Solidity.g4 (ANTLR based grammar) --- docs/grammar.txt | 193 ----------------------------------------- docs/miscellaneous.rst | 4 +- 2 files changed, 2 insertions(+), 195 deletions(-) delete mode 100644 docs/grammar.txt diff --git a/docs/grammar.txt b/docs/grammar.txt deleted file mode 100644 index b8b2893a22c5..000000000000 --- a/docs/grammar.txt +++ /dev/null @@ -1,193 +0,0 @@ -SourceUnit = (PragmaDirective | ImportDirective | ContractDefinition)* - -// Pragma actually parses anything up to the trailing ';' to be fully forward-compatible. -PragmaDirective = 'pragma' Identifier ([^;]+) ';' - -ImportDirective = 'import' StringLiteral ('as' Identifier)? ';' - | 'import' ('*' | Identifier) ('as' Identifier)? 'from' StringLiteral ';' - | 'import' '{' Identifier ('as' Identifier)? ( ',' Identifier ('as' Identifier)? )* '}' 'from' StringLiteral ';' - -ContractDefinition = 'abstract'? ( 'contract' | 'library' | 'interface' ) Identifier - ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )? - '{' ContractPart* '}' - -ContractPart = StateVariableDeclaration | UsingForDeclaration - | StructDefinition | ModifierDefinition | FunctionDefinition | EventDefinition | EnumDefinition - -InheritanceSpecifier = UserDefinedTypeName ( '(' Expression ( ',' Expression )* ')' )? - -StateVariableDeclaration = TypeName ( 'public' | 'internal' | 'private' | 'constant' | OverrideSpecifier )* Identifier ('=' Expression)? ';' -UsingForDeclaration = 'using' Identifier 'for' ('*' | TypeName) ';' -StructDefinition = 'struct' Identifier '{' - ( VariableDeclaration ';' (VariableDeclaration ';')* ) '}' - -ModifierDefinition = 'modifier' Identifier ParameterList? ( 'virtual' | OverrideSpecifier )* Block -ModifierInvocation = Identifier ( '(' ExpressionList? ')' )? - -FunctionDefinition = FunctionDescriptor ParameterList - ( ModifierInvocation | StateMutability | 'external' | 'public' | 'internal' | 'private' | 'virtual' | OverrideSpecifier )* - ( 'returns' ParameterList )? ( ';' | Block ) - -FunctionDescriptor = 'function' Identifier | 'constructor' | 'fallback' | 'receive' - -OverrideSpecifier = 'override' ( '(' UserDefinedTypeName (',' UserDefinedTypeName)* ')' )? - -EventDefinition = 'event' Identifier EventParameterList 'anonymous'? ';' - -EnumValue = Identifier -EnumDefinition = 'enum' Identifier '{' EnumValue? (',' EnumValue)* '}' - -ParameterList = '(' ( Parameter (',' Parameter)* )? ')' -Parameter = TypeName StorageLocation? Identifier? - -EventParameterList = '(' ( EventParameter (',' EventParameter )* )? ')' -EventParameter = TypeName 'indexed'? Identifier? - -FunctionTypeParameterList = '(' ( FunctionTypeParameter (',' FunctionTypeParameter )* )? ')' -FunctionTypeParameter = TypeName StorageLocation? - -// semantic restriction: mappings and structs (recursively) containing mappings -// are not allowed in argument lists -VariableDeclaration = TypeName StorageLocation? Identifier - -TypeName = ElementaryTypeName - | UserDefinedTypeName - | Mapping - | ArrayTypeName - | FunctionTypeName - | ( 'address' 'payable' ) - -UserDefinedTypeName = Identifier ( '.' Identifier )* - -Mapping = 'mapping' '(' ( ElementaryTypeName | UserDefinedTypeName ) '=>' TypeName ')' -ArrayTypeName = TypeName '[' Expression? ']' -FunctionTypeName = 'function' FunctionTypeParameterList ( 'internal' | 'external' | StateMutability )* - ( 'returns' FunctionTypeParameterList )? -StorageLocation = 'memory' | 'storage' | 'calldata' -StateMutability = 'pure' | 'view' | 'payable' - -Block = '{' Statement* '}' -Statement = IfStatement | TryStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement | - ( DoWhileStatement | PlaceholderStatement | Continue | Break | Return | - Throw | EmitStatement | SimpleStatement ) ';' - -ExpressionStatement = Expression -IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )? -TryStatement = 'try' Expression ( 'returns' ParameterList )? Block CatchClause+ -CatchClause = 'catch' ( Identifier? ParameterList )? Block -WhileStatement = 'while' '(' Expression ')' Statement -PlaceholderStatement = '_' -SimpleStatement = VariableDefinition | ExpressionStatement -ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement -InlineAssemblyStatement = 'assembly' StringLiteral? AssemblyBlock -DoWhileStatement = 'do' Statement 'while' '(' Expression ')' -Continue = 'continue' -Break = 'break' -Return = 'return' Expression? -Throw = 'throw' -EmitStatement = 'emit' FunctionCall -VariableDefinition = (VariableDeclaration | '(' VariableDeclaration? (',' VariableDeclaration? )* ')' ) ( '=' Expression )? - -// Precedence by order (see github.com/ethereum/solidity/pull/732) -Expression - = Expression ('++' | '--') - | NewExpression - | IndexAccess - | IndexRangeAccess - | MemberAccess - | FunctionCall - | Expression '{' NameValueList '}' - | '(' Expression ')' - | ('!' | '~' | 'delete' | '++' | '--' | '+' | '-') Expression - | Expression '**' Expression - | Expression ('*' | '/' | '%') Expression - | Expression ('+' | '-') Expression - | Expression ('<<' | '>>') Expression - | Expression '&' Expression - | Expression '^' Expression - | Expression '|' Expression - | Expression ('<' | '>' | '<=' | '>=') Expression - | Expression ('==' | '!=') Expression - | Expression '&&' Expression - | Expression '||' Expression - | Expression '?' Expression ':' Expression - | Expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') Expression - | PrimaryExpression - -PrimaryExpression = BooleanLiteral - | NumberLiteral - | HexLiteral - | StringLiteral - | TupleExpression - | Identifier - | ElementaryTypeNameExpression - -ExpressionList = Expression ( ',' Expression )* -NameValueList = Identifier ':' Expression ( ',' Identifier ':' Expression )* - -FunctionCall = Expression '(' FunctionCallArguments ')' -FunctionCallArguments = '{' NameValueList? '}' - | ExpressionList? - -NewExpression = 'new' TypeName -MemberAccess = Expression '.' Identifier -IndexAccess = Expression '[' Expression? ']' -IndexRangeAccess = Expression '[' Expression? ':' Expression? ']' - -BooleanLiteral = 'true' | 'false' -NumberLiteral = ( HexNumber | DecimalNumber ) (' ' NumberUnit)? -NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether' - | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' -HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') -StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' -Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]* - -HexNumber = '0x' [0-9a-fA-F]+ -DecimalNumber = [0-9]+ ( '.' [0-9]* )? ( [eE] [0-9]+ )? - -TupleExpression = '(' ( Expression? ( ',' Expression? )* )? ')' - | '[' ( Expression ( ',' Expression )* )? ']' - -ElementaryTypeNameExpression = ElementaryTypeName - -ElementaryTypeName = 'address' | 'bool' | 'string' | Int | Uint | Byte | Fixed | Ufixed - -Int = 'int' | 'int8' | 'int16' | 'int24' | 'int32' | 'int40' | 'int48' | 'int56' | 'int64' | 'int72' | 'int80' | 'int88' | 'int96' | 'int104' | 'int112' | 'int120' | 'int128' | 'int136' | 'int144' | 'int152' | 'int160' | 'int168' | 'int176' | 'int184' | 'int192' | 'int200' | 'int208' | 'int216' | 'int224' | 'int232' | 'int240' | 'int248' | 'int256' - -Uint = 'uint' | 'uint8' | 'uint16' | 'uint24' | 'uint32' | 'uint40' | 'uint48' | 'uint56' | 'uint64' | 'uint72' | 'uint80' | 'uint88' | 'uint96' | 'uint104' | 'uint112' | 'uint120' | 'uint128' | 'uint136' | 'uint144' | 'uint152' | 'uint160' | 'uint168' | 'uint176' | 'uint184' | 'uint192' | 'uint200' | 'uint208' | 'uint216' | 'uint224' | 'uint232' | 'uint240' | 'uint248' | 'uint256' - -Byte = 'byte' | 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' | 'bytes6' | 'bytes7' | 'bytes8' | 'bytes9' | 'bytes10' | 'bytes11' | 'bytes12' | 'bytes13' | 'bytes14' | 'bytes15' | 'bytes16' | 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32' - -Fixed = 'fixed' | ( 'fixed' [0-9]+ 'x' [0-9]+ ) - -Ufixed = 'ufixed' | ( 'ufixed' [0-9]+ 'x' [0-9]+ ) - - -AssemblyBlock = '{' AssemblyStatement* '}' - -AssemblyStatement = AssemblyBlock - | AssemblyFunctionDefinition - | AssemblyVariableDeclaration - | AssemblyAssignment - | AssemblyIf - | AssemblyExpression - | AssemblySwitch - | AssemblyForLoop - | AssemblyBreakContinue - | AssemblyLeave -AssemblyFunctionDefinition = - 'function' Identifier '(' AssemblyIdentifierList? ')' - ( '->' AssemblyIdentifierList )? AssemblyBlock -AssemblyVariableDeclaration = 'let' AssemblyIdentifierList ( ':=' AssemblyExpression )? -AssemblyAssignment = AssemblyIdentifierList ':=' AssemblyExpression -AssemblyExpression = AssemblyFunctionCall | Identifier | Literal -AssemblyIf = 'if' AssemblyExpression AssemblyBlock -AssemblySwitch = 'switch' AssemblyExpression ( AssemblyCase+ AssemblyDefault? | AssemblyDefault ) -AssemblyCase = 'case' Literal AssemblyBlock -AssemblyDefault = 'default' AssemblyBlock -AssemblyForLoop = 'for' AssemblyBlock AssemblyExpression AssemblyBlock AssemblyBlock -AssemblyBreakContinue = 'break' | 'continue' -AssemblyLeave = 'leave' -AssemblyFunctionCall = Identifier '(' ( AssemblyExpression ( ',' AssemblyExpression )* )? ')' - -AssemblyIdentifierList = Identifier ( ',' Identifier )* diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 085bf99e7638..b4082fceda16 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -809,5 +809,5 @@ These keywords are reserved in Solidity. They might become part of the syntax in Language Grammar ================ -.. literalinclude:: grammar.txt - :language: none +.. literalinclude:: Solidity.g4 + :language: antlr From c002cae6914a7d5d8d48450e55f12c290e321418 Mon Sep 17 00:00:00 2001 From: a3d4 Date: Mon, 30 Mar 2020 15:18:51 +0200 Subject: [PATCH 133/165] Fix #8450. Prevented internal compiler errors when assigning nested tuples. --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 4 ++-- .../semanticTests/types/tuple_in_tuple.sol | 24 +++++++++++++++++++ .../tupleAssignments/tuple_in_tuple_long.sol | 12 ++++++++++ .../tupleAssignments/tuple_in_tuple_short.sol | 6 +++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/types/tuple_in_tuple.sol create mode 100644 test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol create mode 100644 test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol diff --git a/Changelog.md b/Changelog.md index 96f3a144484c..f269e049f573 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: Bugfixes: * Inline Assembly: Fix internal error when accessing invalid constant variables. * Reference Resolver: Fix internal error when accessing invalid struct members. + * Type Checker: Fix internal errors when assigning nested tuples. * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. * JSON AST: Always add pointer suffix for memory reference types. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1345fbf90008..784701d22767 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1317,11 +1317,11 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& if (auto const* tupleExpression = dynamic_cast(&_expression)) { auto const* tupleType = dynamic_cast(&_type); - auto const& types = tupleType ? tupleType->components() : vector { &_type }; + auto const& types = tupleType && tupleExpression->components().size() > 1 ? tupleType->components() : vector { &_type }; solAssert( tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(), - "Array sizes don't match or no errors generated." + "Array sizes don't match and no errors generated." ); for (size_t i = 0; i < min(tupleExpression->components().size(), types.size()); i++) diff --git a/test/libsolidity/semanticTests/types/tuple_in_tuple.sol b/test/libsolidity/semanticTests/types/tuple_in_tuple.sol new file mode 100644 index 000000000000..d9737a807832 --- /dev/null +++ b/test/libsolidity/semanticTests/types/tuple_in_tuple.sol @@ -0,0 +1,24 @@ +contract test { + function f0() public returns(int, bool) { + int a; + bool b; + ((a, b)) = (2, true); + return (a, b); + } + function f1() public returns(int) { + int a; + (((a, ), )) = ((1, 2) ,3); + return a; + } + function f2() public returns(int) { + int a; + (((, a),)) = ((1, 2), 3); + return a; + } +} +// ==== +// compileViaYul: also +// ---- +// f0() -> 2, true +// f1() -> 1 +// f2() -> 2 diff --git a/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol new file mode 100644 index 000000000000..2fa48cfb1b5a --- /dev/null +++ b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_long.sol @@ -0,0 +1,12 @@ +contract C { + function f() { + (((((((((((,2),)),)),),))=4))); + } +} +// ---- +// SyntaxError: (15-69): No visibility specified. Did you intend to add "public"? +// TypeError: (46-47): Expression has to be an lvalue. +// TypeError: (60-61): Type int_const 4 is not implicitly convertible to expected type tuple(tuple(tuple(tuple(tuple(,int_const 2),),),),). +// TypeError: (37-61): Tuple component cannot be empty. +// TypeError: (36-62): Tuple component cannot be empty. +// TypeError: (35-63): Tuple component cannot be empty. diff --git a/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol new file mode 100644 index 000000000000..2a5d62752ce3 --- /dev/null +++ b/test/libsolidity/syntaxTests/tupleAssignments/tuple_in_tuple_short.sol @@ -0,0 +1,6 @@ +contract C { + function f() public pure { + int a; + (((a,),)) = ((1,2),3); + } +} From 64ae889dd71b7ed70a221c8eda879c67836b4c57 Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Sun, 29 Mar 2020 00:02:44 +0100 Subject: [PATCH 134/165] Enabling pragma with > in minimum version check --- .circleci/config.yml | 14 ++++ docs/examples/blind-auction.rst | 2 +- docs/using-the-compiler.rst | 4 +- scripts/docs_version_pragma_check.sh | 120 +++++++++++++++++++++++---- 4 files changed, 123 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ac1dda7dd0c9..9ccf7a6638ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -651,6 +651,19 @@ jobs: SOLTEST_FLAGS: --no-smt ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 + t_ubu_pragma_docs_test: &t_ubu_pragma_docs_test + docker: + - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + environment: + TERM: xterm + steps: + - checkout + - attach_workspace: + at: build + - run: *run_docs_version_pragma_check + - store_test_results: *store_test_results + - store_artifacts: *artifacts_test_results + t_ems_solcjs: docker: - image: ethereum/solidity-buildpack-deps:ubuntu1904 @@ -802,6 +815,7 @@ workflows: - b_ubu: *workflow_trigger_on_tags - b_ubu18: *workflow_trigger_on_tags - t_ubu_cli: *workflow_ubuntu1904 + - t_ubu_pragma_docs_test: *workflow_ubuntu1904 - t_ubu_soltest: *workflow_ubuntu1904 - b_ubu_clang: *workflow_trigger_on_tags - t_ubu_clang_soltest: *workflow_ubuntu1904_clang diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index 4461bfc654f9..f2034272a889 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -184,7 +184,7 @@ invalid bids. :: - pragma solidity >0.4.23 <0.7.0; + pragma solidity >=0.5.0 <0.7.0; contract BlindAuction { struct Bid { diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 12fe4b3f9917..8d647a4a7c09 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -605,8 +605,8 @@ Assume you have the following contracts you want to update declared in ``Source. .. code-block:: none - // This will not compile - pragma solidity >0.4.23; + // This will not compile after 0.5.0 + pragma solidity >0.4.23 <0.5.0; contract Updateable { function run() public view returns (bool); diff --git a/scripts/docs_version_pragma_check.sh b/scripts/docs_version_pragma_check.sh index a66798841e49..c56bdc6c98c7 100755 --- a/scripts/docs_version_pragma_check.sh +++ b/scripts/docs_version_pragma_check.sh @@ -32,6 +32,97 @@ SOLIDITY_BUILD_DIR=${SOLIDITY_BUILD_DIR:-build} source "${REPO_ROOT}/scripts/common.sh" source "${REPO_ROOT}/scripts/common_cmdline.sh" +function versionGreater() +{ + v1=$1 + v2=$2 + ver1=( ${v1//./ } ) + ver2=( ${v2//./ } ) + + if (( ${ver1[0]} > ${ver2[0]} )) + then + return 0 + elif (( ${ver1[0]} == ${ver2[0]} )) && (( ${ver1[1]} > ${ver2[1]} )) + then + return 0 + elif (( ${ver1[0]} == ${ver2[0]} )) && (( ${ver1[1]} == ${ver2[1]} )) && (( ${ver1[2]} > ${ver2[2]} )) + then + return 0 + fi + return 1 +} + +function versionEqual() +{ + if [ "$1" == "$2" ] + then + return 0 + fi + return 1 +} + +function getAllAvailableVersions() +{ + allVersions=() + local allListedVersions=( $( + wget -q -O- https://ethereum.github.io/solc-bin/bin/list.txt | + grep -Po '(?<=soljson-v)\d+.\d+.\d+(?=\+commit)' | + sort -V + ) ) + for listed in "${allListedVersions[@]}" + do + if versionGreater "$listed" "0.4.10" + then + allVersions+=( $listed ) + fi + done +} + +function findMinimalVersion() +{ + local f=$1 + local greater=false + local pragmaVersion + + # Get minimum compiler version defined by pragma + if (grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f" >/dev/null) + then + pragmaVersion="$(grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f")" + sign=">=" + elif (grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f" >/dev/null) + then + pragmaVersion="$(grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f")" + sign="^" + elif (grep -Po '(?<=pragma solidity >)\d+.\d+.\d+' "$f" >/dev/null) + then + pragmaVersion="$(grep -Po '(?<=pragma solidity >)\d+.\d+.\d+' "$f")" + sign=">" + greater=true; + else + printError "No valid pragma statement in file. Skipping..." + return + fi + + version="" + for ver in "${allVersions[@]}" + do + if versionGreater "$ver" "$pragmaVersion" + then + minVersion="$ver" + break + elif ([ $greater == false ]) && versionEqual "$ver" "$pragmaVersion" + then + version="$ver" + break + fi + done + + if [ -z version ] + then + printError "No release $sign$pragmaVersion was listed in available releases!" + fi +} + printTask "Verifying that all examples from the documentation have the correct version range..." SOLTMPDIR=$(mktemp -d) ( @@ -39,6 +130,8 @@ SOLTMPDIR=$(mktemp -d) cd "$SOLTMPDIR" "$REPO_ROOT"/scripts/isolate_tests.py "$REPO_ROOT"/docs/ docs + getAllAvailableVersions + for f in *.sol do # The contributors guide uses syntax tests, but we cannot @@ -61,27 +154,26 @@ SOLTMPDIR=$(mktemp -d) # ignore warnings in this case opts="$opts -o" - # Get minimum compiler version defined by pragma - if (grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f" >/dev/null); then - version="$(grep -Po '(?<=pragma solidity >=)\d+.\d+.\d+' "$f")" - if (echo $version | grep -Po '(?<=0.4.)\d+' >/dev/null); then - patch=$(echo $version | grep -Po '(?<=0.4.)\d+') - if (( patch < 11 )); then - version="0.4.11" # first available release on github - fi - fi - elif (grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f" >/dev/null); then - version="$(grep -Po '(?<=pragma solidity \^)\d+.\d+.\d+' "$f")" + findMinimalVersion $f + if [ -z "$version" ] + then + continue fi opts="$opts -v $version" solc_bin="solc-$version" echo "$solc_bin" - if [[ ! -f "$solc_bin" ]]; then + if [[ ! -f "$solc_bin" ]] + then echo "Downloading release from github..." - wget https://github.com/ethereum/solidity/releases/download/v$version/solc-static-linux - mv solc-static-linux $solc_bin + if wget -q https://github.com/ethereum/solidity/releases/download/v$version/solc-static-linux >/dev/null + then + mv solc-static-linux $solc_bin + else + printError "No release $version was found on github!" + continue + fi fi ln -sf "$solc_bin" "solc" From 3e649eb8e1b85020de3aea52eb53e57d0c1743cb Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 30 Mar 2020 20:01:50 -0500 Subject: [PATCH 135/165] Disallow access to functions from inline assembly. --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 2 ++ .../inlineAssembly/assignment_from_functiontype.sol | 2 ++ .../inlineAssembly/assignment_from_functiontype2.sol | 10 ++++++++++ 4 files changed, 15 insertions(+) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype2.sol diff --git a/Changelog.md b/Changelog.md index 4d132d6849da..b512f9eb2431 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Compiler Features: Bugfixes: * Inline Assembly: Fix internal error when accessing invalid constant variables. + * Inline Assembly: Fix internal error when accessing functions. * Reference Resolver: Fix internal error when accessing invalid struct members. * Type Checker: Fix internal errors when assigning nested tuples. * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 784701d22767..8067580c8d7d 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -740,6 +740,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(!!declaration->type(), "Type of declaration required but not yet determined."); if (dynamic_cast(declaration)) { + m_errorReporter.declarationError(_identifier.location, "Access to functions is not allowed in inline assembly."); + return size_t(-1); } else if (dynamic_cast(declaration)) { diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol index ecda3e994eaa..625502f25899 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype.sol @@ -5,3 +5,5 @@ contract C { } } } +// ---- +// DeclarationError: (72-73): Access to functions is not allowed in inline assembly. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype2.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype2.sol new file mode 100644 index 000000000000..2fc49b1dbab1 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_from_functiontype2.sol @@ -0,0 +1,10 @@ +contract C { + function f() public pure {} + constructor() public { + assembly { + let x := f + } + } +} +// ---- +// DeclarationError: (112-113): Access to functions is not allowed in inline assembly. From 9c4a02db0fb901cea81bca06e3f0b73f3c9e5f16 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 19 Mar 2020 17:57:55 +0100 Subject: [PATCH 136/165] Documentation for immutables. --- docs/contracts/constant-state-variables.rst | 73 ++++++++++++++++----- docs/miscellaneous.rst | 1 + docs/types/reference-types.rst | 6 ++ 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst index 33511f020d47..7a0a7380a555 100644 --- a/docs/contracts/constant-state-variables.rst +++ b/docs/contracts/constant-state-variables.rst @@ -1,11 +1,49 @@ .. index:: ! constant -************************ -Constant State Variables -************************ +************************************** +Constant and Immutable State Variables +************************************** -State variables can be declared as ``constant``. In this case, they have to be -assigned from an expression which is a constant at compile time. Any expression +State variables can be declared as ``constant`` or ``immutable``. +In both cases, the variables cannot be modified after the contract has been constructed. +For ``constant`` variables, the value has to be fixed at compile-time, while +for ``immutable``, it can still be assigned at construction time. + +The compiler does not reserve a storage slot for these variables, and every occurrence is +replaced by the respective value. + +Not all types for constants and immutables are implemented at this time. The only supported types are +`strings `_ (only for constants) and `value types `_. + +:: + + pragma solidity >0.6.4 <0.7.0; + + contract C { + uint constant X = 32**22 + 8; + string constant TEXT = "abc"; + bytes32 constant MY_HASH = keccak256("abc"); + uint immutable decimals; + uint immutable maxBalance; + address immutable owner = msg.sender; + + constructor(uint _decimals, address _reference) public { + decimals = _decimals; + // Assignments to immutables can even access the environment. + maxBalance = _reference.balance; + } + + function isBalanceTooHigh(address _other) public view returns (bool) { + return _other.balance > maxBalance; + } + } + + +Constant +======== + +For ``constant`` variables, the value has to be a constant at compile time and it has to be +assigned where the variable is declared. Any expression that accesses storage, blockchain data (e.g. ``now``, ``address(this).balance`` or ``block.number``) or execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions @@ -18,18 +56,17 @@ The reason behind allowing side-effects on the memory allocator is that it should be possible to construct complex objects like e.g. lookup-tables. This feature is not yet fully usable. -The compiler does not reserve a storage slot for these variables, and every occurrence is -replaced by the respective constant expression (which might be computed to a single value by the optimizer). - -Not all types for constants are implemented at this time. The only supported types are -value types and strings. +Immutable +========= -:: +Variables declared as ``immutable`` are a bit less restricted than those +declared as ``constant``: Immutable variables can be assigned an arbitrary +value in the constructor of the contract or at the point of their declaration. +They cannot be read during construction time and can only be assigned once. - pragma solidity >=0.4.0 <0.7.0; - - contract C { - uint constant X = 32**22 + 8; - string constant TEXT = "abc"; - bytes32 constant MY_HASH = keccak256("abc"); - } +The contract creation code generated by the compiler will modify the +contract's runtime code before it is returned by replacing all references +to immutables by the values assigned to the them. This is important if +you are comparing the +runtime code generated by the compiler with the one actually stored in the +blockchain. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index b4082fceda16..3c30fec86d1a 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -788,6 +788,7 @@ Modifiers - ``view`` for functions: Disallows modification of state. - ``payable`` for functions: Allows them to receive Ether together with a call. - ``constant`` for state variables: Disallows assignment (except initialisation), does not occupy storage slot. +- ``immutable`` for state variables: Allows exactly one assignment at construction time and is constant afterwards. Is stored in code. - ``anonymous`` for events: Does not store event signature as topic. - ``indexed`` for event parameters: Stores the parameter as topic. - ``virtual`` for functions and modifiers: Allows the function's or modifier's diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 275e8b575121..1566a88591d8 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -124,6 +124,12 @@ Accessing an array past its end causes a failing assertion. Methods ``.push()`` to append a new element at the end of the array, where ``.push()`` appends a zero-initialized element and returns a reference to it. +.. index:: ! string, ! bytes + +.. _strings: + +.. _bytes: + ``bytes`` and ``strings`` as Arrays ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 2853cba3e5c98fe828be722391c4c5e6417fc4be Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 1 Apr 2020 12:13:32 +0200 Subject: [PATCH 137/165] Fix call to internalDispatch. --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index b5d9589c0348..8a98e8d3651e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -568,7 +568,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } define(_functionCall) << - m_context.internalDispatch(functionType->parameterTypes().size(), functionType->returnParameterTypes().size()) << + m_context.internalDispatch( + TupleType(functionType->parameterTypes()).sizeOnStack(), + TupleType(functionType->returnParameterTypes()).sizeOnStack() + ) << "(" << IRVariable(_functionCall.expression()).part("functionIdentifier").name() << joinHumanReadablePrefixed(args) << From fe9f8d520cd17e0bf69e6ee507db05fa8a5bf833 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 1 Apr 2020 14:02:30 +0200 Subject: [PATCH 138/165] Restrict size for dynamic memory array creation. --- Changelog.md | 4 ++++ libsolidity/codegen/ExpressionCompiler.cpp | 6 +++++ .../array/create_memory_array_too_large.sol | 24 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 test/libsolidity/semanticTests/array/create_memory_array_too_large.sol diff --git a/Changelog.md b/Changelog.md index b512f9eb2431..f20b05aa54d9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ ### 0.6.5 (unreleased) +Important Bugfixes: + * Code Generator: Restrict the size of dynamic memory arrays to 64 bits during creation at runtime fixing a possible overflow. + + Language Features: diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 58992426be37..fed3751fa6cb 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -995,6 +995,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // Fetch requested length. acceptAndConvert(*arguments[0], *TypeProvider::uint256()); + // Make sure we can allocate memory without overflow + m_context << u256(0xffffffffffffffff); + m_context << Instruction::DUP2; + m_context << Instruction::GT; + m_context.appendConditionalRevert(); + // Stack: requested_length utils().fetchFreeMemoryPointer(); diff --git a/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol new file mode 100644 index 000000000000..c42f8486217b --- /dev/null +++ b/test/libsolidity/semanticTests/array/create_memory_array_too_large.sol @@ -0,0 +1,24 @@ +contract C { + function f() public returns (uint256) { + uint256 l = 2**256 / 32; + // This used to work without causing an error. + uint256[] memory x = new uint256[](l); + uint256[] memory y = new uint256[](1); + x[1] = 42; + // This used to overwrite the value written above. + y[0] = 23; + return x[1]; + } + function g() public returns (uint256) { + uint256 l = 2**256 / 2 + 1; + // This used to work without causing an error. + uint16[] memory x = new uint16[](l); + uint16[] memory y = new uint16[](1); + x[2] = 42; + // This used to overwrite the value written above. + y[0] = 23; + return x[2]; + }} +// ---- +// f() -> FAILURE +// g() -> FAILURE From d343143be763a64c2ccbb8302a2d00353d13f64f Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Wed, 1 Apr 2020 18:16:47 +0200 Subject: [PATCH 139/165] [docs] Renaming CI job for documentation pragma version check --- .circleci/config.yml | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9ccf7a6638ff..23da90b8f35a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -122,8 +122,8 @@ defaults: name: command line tests command: ./test/cmdlineTests.sh - - run_docs_version_pragma_check: &run_docs_version_pragma_check - name: docs version pragma check + - run_docs_pragma_min_version: &run_docs_pragma_min_version + name: docs pragma version check command: ./scripts/docs_version_pragma_check.sh - test_ubuntu1604_clang: &test_ubuntu1604_clang @@ -351,6 +351,15 @@ jobs: pip install --user z3-solver - run: *run_proofs + chk_docs_pragma_min_version: + docker: + - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> + environment: + TERM: xterm + steps: + - checkout + - run: *run_docs_pragma_min_version + b_ubu_clang: &build_ubuntu1904_clang docker: - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-<< pipeline.parameters.ubuntu-1904-clang-docker-image-rev >> @@ -621,7 +630,6 @@ jobs: - attach_workspace: at: build - run: *run_cmdline_tests - - run: *run_docs_version_pragma_check - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results @@ -651,19 +659,6 @@ jobs: SOLTEST_FLAGS: --no-smt ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 - t_ubu_pragma_docs_test: &t_ubu_pragma_docs_test - docker: - - image: ethereum/solidity-buildpack-deps:ubuntu1904-<< pipeline.parameters.ubuntu-1904-docker-image-rev >> - environment: - TERM: xterm - steps: - - checkout - - attach_workspace: - at: build - - run: *run_docs_version_pragma_check - - store_test_results: *store_test_results - - store_artifacts: *artifacts_test_results - t_ems_solcjs: docker: - image: ethereum/solidity-buildpack-deps:ubuntu1904 @@ -799,6 +794,7 @@ workflows: - chk_proofs: *workflow_trigger_on_tags - chk_pylint: *workflow_trigger_on_tags - chk_antlr_grammar: *workflow_trigger_on_tags + - chk_docs_pragma_min_version: *workflow_trigger_on_tags # build-only - b_docs: *workflow_trigger_on_tags @@ -815,7 +811,6 @@ workflows: - b_ubu: *workflow_trigger_on_tags - b_ubu18: *workflow_trigger_on_tags - t_ubu_cli: *workflow_ubuntu1904 - - t_ubu_pragma_docs_test: *workflow_ubuntu1904 - t_ubu_soltest: *workflow_ubuntu1904 - b_ubu_clang: *workflow_trigger_on_tags - t_ubu_clang_soltest: *workflow_ubuntu1904_clang From 06d184712cef983fff519cf231ae9aed9131d2c9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 1 Apr 2020 16:42:23 +0200 Subject: [PATCH 140/165] Add buglist entry. --- docs/bugs.json | 8 +++++ docs/bugs_by_version.json | 75 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/docs/bugs.json b/docs/bugs.json index 388bd4b56e61..066e17e93b8a 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "MemoryArrayCreationOverflow", + "summary": "The creation of very large memory arrays can result in overlapping memory regions and thus memory corruption.", + "description": "No runtime overflow checks were performed for the length of memory arrays during creation. In cases for which the memory size of an array in bytes, i.e. the array length times 32, is larger than 2^256-1, the memory allocation will overflow, potentially resulting in overlapping memory areas. The length of the array is still stored correctly, so copying or iterating over such an array will result in out-of-gas.", + "introduced": "0.2.0", + "fixed": "0.6.5", + "severity": "low" + }, { "name": "YulOptimizerRedundantAssignmentBreakContinue", "summary": "The Yul optimizer can remove essential assignments to variables declared inside for loops when Yul's continue or break statement is used. You are unlikely to be affected if you do not use inline assembly with for loops and continue and break statements.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index d8daf565e9e7..0d0f30c48e71 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -151,6 +151,7 @@ }, "0.2.0": { "bugs": [ + "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", @@ -171,6 +172,7 @@ }, "0.2.1": { "bugs": [ + "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", @@ -191,6 +193,7 @@ }, "0.2.2": { "bugs": [ + "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", @@ -211,6 +214,7 @@ }, "0.3.0": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -233,6 +237,7 @@ }, "0.3.1": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -254,6 +259,7 @@ }, "0.3.2": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -275,6 +281,7 @@ }, "0.3.3": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -295,6 +302,7 @@ }, "0.3.4": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -315,6 +323,7 @@ }, "0.3.5": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -335,6 +344,7 @@ }, "0.3.6": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -353,6 +363,7 @@ }, "0.4.0": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -371,6 +382,7 @@ }, "0.4.1": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -389,6 +401,7 @@ }, "0.4.10": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -405,6 +418,7 @@ }, "0.4.11": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -420,6 +434,7 @@ }, "0.4.12": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -434,6 +449,7 @@ }, "0.4.13": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -448,6 +464,7 @@ }, "0.4.14": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -461,6 +478,7 @@ }, "0.4.15": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -473,6 +491,7 @@ }, "0.4.16": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -487,6 +506,7 @@ }, "0.4.17": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -502,6 +522,7 @@ }, "0.4.18": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -516,6 +537,7 @@ }, "0.4.19": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -531,6 +553,7 @@ }, "0.4.2": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -548,6 +571,7 @@ }, "0.4.20": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -563,6 +587,7 @@ }, "0.4.21": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -578,6 +603,7 @@ }, "0.4.22": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -593,6 +619,7 @@ }, "0.4.23": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -607,6 +634,7 @@ }, "0.4.24": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -621,6 +649,7 @@ }, "0.4.25": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -633,6 +662,7 @@ }, "0.4.26": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -642,6 +672,7 @@ }, "0.4.3": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -658,6 +689,7 @@ }, "0.4.4": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", "ExpExponentCleanup", @@ -673,6 +705,7 @@ }, "0.4.5": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -690,6 +723,7 @@ }, "0.4.6": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", "IncorrectEventSignatureInLibraries_0.4.x", @@ -706,6 +740,7 @@ }, "0.4.7": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -722,6 +757,7 @@ }, "0.4.8": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -738,6 +774,7 @@ }, "0.4.9": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -754,6 +791,7 @@ }, "0.5.0": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -766,6 +804,7 @@ }, "0.5.1": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -778,6 +817,7 @@ }, "0.5.10": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers" @@ -786,6 +826,7 @@ }, "0.5.11": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], @@ -793,6 +834,7 @@ }, "0.5.12": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], @@ -800,6 +842,7 @@ }, "0.5.13": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], @@ -807,6 +850,7 @@ }, "0.5.14": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2LoopYulOptimizer" @@ -815,6 +859,7 @@ }, "0.5.15": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" ], @@ -822,16 +867,20 @@ }, "0.5.16": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden" ], "released": "2020-01-02" }, "0.5.17": { - "bugs": [], + "bugs": [ + "MemoryArrayCreationOverflow" + ], "released": "2020-03-17" }, "0.5.2": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -844,6 +893,7 @@ }, "0.5.3": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -856,6 +906,7 @@ }, "0.5.4": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -868,6 +919,7 @@ }, "0.5.5": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", "ABIEncoderV2StorageArrayWithMultiSlotElement", @@ -882,6 +934,7 @@ }, "0.5.6": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", @@ -896,6 +949,7 @@ }, "0.5.7": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", "SignedArrayStorageCopy", @@ -908,6 +962,7 @@ }, "0.5.8": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", @@ -919,6 +974,7 @@ }, "0.5.9": { "bugs": [ + "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", @@ -929,24 +985,33 @@ }, "0.6.0": { "bugs": [ + "MemoryArrayCreationOverflow", "YulOptimizerRedundantAssignmentBreakContinue" ], "released": "2019-12-17" }, "0.6.1": { - "bugs": [], + "bugs": [ + "MemoryArrayCreationOverflow" + ], "released": "2020-01-02" }, "0.6.2": { - "bugs": [], + "bugs": [ + "MemoryArrayCreationOverflow" + ], "released": "2020-01-27" }, "0.6.3": { - "bugs": [], + "bugs": [ + "MemoryArrayCreationOverflow" + ], "released": "2020-02-18" }, "0.6.4": { - "bugs": [], + "bugs": [ + "MemoryArrayCreationOverflow" + ], "released": "2020-03-10" } } \ No newline at end of file From 616fd8df1ef87bc43929469edf44f4a9f6b00af2 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Tue, 31 Mar 2020 20:42:05 -0500 Subject: [PATCH 141/165] Apply modernize-use-nullptr. --- test/boostTest.cpp | 2 +- tools/yulPhaser/SimulationRNG.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 5a76a3f18886..fd7bca132372 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -187,7 +187,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) if (solidity::test::CommonOptions::get().disableSMT) removeTestSuite("SMTChecker"); - return 0; + return nullptr; } // BOOST_TEST_DYN_LINK should be defined if user want to link against shared boost test library diff --git a/tools/yulPhaser/SimulationRNG.cpp b/tools/yulPhaser/SimulationRNG.cpp index 1103db5a8bc5..2b596f4ed732 100644 --- a/tools/yulPhaser/SimulationRNG.cpp +++ b/tools/yulPhaser/SimulationRNG.cpp @@ -52,5 +52,5 @@ uint32_t SimulationRNG::generateSeed() // This is not a secure way to seed the generator but it's good enough for simulation purposes. // The only thing that matters for us is that the sequence is different on each run and that // it fits the expected distribution. It does not have to be 100% unpredictable. - return time(0); + return time(nullptr); } From 77ea896b68f844728f0adce34166563fd702a24f Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 2 Apr 2020 08:34:20 +0200 Subject: [PATCH 142/165] Properly handle assignments of immutables at declaration. --- libsolidity/codegen/ContractCompiler.cpp | 2 +- libsolidity/codegen/ExpressionCompiler.cpp | 5 ++++- libsolidity/codegen/LValue.cpp | 1 + .../semanticTests/immutable/assign_at_declaration.sol | 8 ++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/immutable/assign_at_declaration.sol diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 50fb030d238f..49b08b6dae7d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -550,7 +550,7 @@ void ContractCompiler::initializeStateVariables(ContractDefinition const& _contr { solAssert(!_contract.isLibrary(), "Tried to initialize state variables of library."); for (VariableDeclaration const* variable: _contract.stateVariables()) - if (variable->value() && !variable->isConstant() && !variable->immutable()) + if (variable->value() && !variable->isConstant()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals).appendStateVariableInitialization(*variable); } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index fed3751fa6cb..a406cdeb843f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -73,7 +73,10 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c utils().convertType(*type, *_varDecl.annotation().type); type = _varDecl.annotation().type; } - StorageItem(m_context, _varDecl).storeValue(*type, _varDecl.location(), true); + if (_varDecl.immutable()) + ImmutableItem(m_context, _varDecl).storeValue(*type, _varDecl.location(), true); + else + StorageItem(m_context, _varDecl).storeValue(*type, _varDecl.location(), true); } void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration const& _varDecl) diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 4b1c80ede88d..3a04d6f92529 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -183,6 +183,7 @@ void ImmutableItem::setToZero(SourceLocation const&, bool) const StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): StorageItem(_compilerContext, *_declaration.annotation().type) { + solAssert(!_declaration.immutable(), ""); auto const& location = m_context.storageLocationOfVariable(_declaration); m_context << location.first << u256(location.second); } diff --git a/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol new file mode 100644 index 000000000000..3f71a31e0fe0 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/assign_at_declaration.sol @@ -0,0 +1,8 @@ +contract A { + uint8 immutable a = 2; + function f() public view returns (uint) { + return a; + } +} +// ---- +// f() -> 2 From 79387b2adaea7ba869ca9c8ad6c1d514fa5e323d Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 2 Apr 2020 12:27:38 +0530 Subject: [PATCH 143/165] Removed redundant declaration check; changed relevant test cases --- libsolidity/analysis/TypeChecker.cpp | 12 +----------- .../syntaxTests/array/uninitialized_storage_var.sol | 6 ++++-- .../211_uninitialized_mapping_array_variable.sol | 2 +- .../233_non_initialized_references.sol | 2 +- .../syntaxTests/parsing/arrays_in_expressions.sol | 1 - 5 files changed, 7 insertions(+), 16 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1345fbf90008..4f4cbe379978 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1061,17 +1061,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) if (!varDecl.annotation().type) m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed."); - if (auto ref = dynamic_cast(type(varDecl))) - { - if (ref->dataStoredIn(DataLocation::Storage)) - { - string errorText{"Uninitialized storage pointer."}; - solAssert(varDecl.referenceLocation() != VariableDeclaration::Location::Unspecified, "Expected a specified location at this point"); - solAssert(m_scope, ""); - m_errorReporter.declarationError(varDecl.location(), errorText); - } - } - else if (dynamic_cast(type(varDecl))) + if (dynamic_cast(type(varDecl))) m_errorReporter.typeError( varDecl.location(), "Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable." diff --git a/test/libsolidity/syntaxTests/array/uninitialized_storage_var.sol b/test/libsolidity/syntaxTests/array/uninitialized_storage_var.sol index f3be9071501e..4966b4e858fa 100644 --- a/test/libsolidity/syntaxTests/array/uninitialized_storage_var.sol +++ b/test/libsolidity/syntaxTests/array/uninitialized_storage_var.sol @@ -2,8 +2,10 @@ contract C { function f() public { uint[] storage x; uint[10] storage y; + x; + y; } } // ---- -// DeclarationError: (38-54): Uninitialized storage pointer. -// DeclarationError: (58-76): Uninitialized storage pointer. +// TypeError: (80-81): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (85-86): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/211_uninitialized_mapping_array_variable.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/211_uninitialized_mapping_array_variable.sol index edae7549dd82..c43dbad6d0b8 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/211_uninitialized_mapping_array_variable.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/211_uninitialized_mapping_array_variable.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// DeclarationError: (52-85): Uninitialized storage pointer. +// TypeError: (95-96): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/233_non_initialized_references.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/233_non_initialized_references.sol index a0b6f71e7d0c..68e3b2c44861 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/233_non_initialized_references.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/233_non_initialized_references.sol @@ -8,4 +8,4 @@ contract C { } } // ---- -// DeclarationError: (84-95): Uninitialized storage pointer. +// TypeError: (105-106): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/parsing/arrays_in_expressions.sol b/test/libsolidity/syntaxTests/parsing/arrays_in_expressions.sol index 4c1f96e6e516..9035caa25703 100644 --- a/test/libsolidity/syntaxTests/parsing/arrays_in_expressions.sol +++ b/test/libsolidity/syntaxTests/parsing/arrays_in_expressions.sol @@ -3,4 +3,3 @@ contract c { } // ---- // TypeError: (39-58): Type int_const 7 is not implicitly convertible to expected type contract c[10] storage pointer. -// DeclarationError: (60-83): Uninitialized storage pointer. From aec0ae8ec1d9d0fda5b64356bb4b357a7e7125ef Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 2 Apr 2020 15:45:04 +0530 Subject: [PATCH 144/165] Extended test-coverage for storage declaration --- .../assembly/for_declaration_err.sol | 38 +++++++++++ .../assembly/for_declaration_fine.sol | 19 ++++++ .../assembly/if_declaration_err.sol | 13 ++++ .../returning_function_declaration.sol | 15 +++++ .../reverting_function_declaration.sol | 15 +++++ .../assembly/stub_declaration.sol | 12 ++++ .../assembly/switch_declaration_err.sol | 33 ++++++++++ .../assembly/switch_declaration_fine.sol | 31 +++++++++ .../storageReturn/dowhile_declaration_err.sol | 66 +++++++++++++++++++ .../dowhile_declaration_fine.sol | 44 +++++++++++++ .../storageReturn/for_declaration_err.sol | 20 ++++++ .../storageReturn/for_declaration_fine.sol | 17 +++++ .../storageReturn/if_declaration_err.sol | 22 +++++++ .../storageReturn/if_declaration_fine.sol | 39 +++++++++++ .../modifier_declaration_fine.sol | 20 ++++++ .../storageReturn/revert_declaration_fine.sol | 11 ++++ .../short_circuit_declaration_err.sol | 24 +++++++ .../short_circuit_declaration_fine.sol | 15 +++++ .../storageReturn/smoke_declaration.sol | 17 +++++ .../storageReturn/ternary_declaration_err.sol | 17 +++++ .../ternary_declaration_fine.sol | 20 ++++++ .../storageReturn/try_declaration_err.sol | 42 ++++++++++++ .../storageReturn/try_declaration_fine.sol | 30 +++++++++ .../storageReturn/tuple_declaration_fine.sol | 17 +++++ .../storageReturn/while_declaration_err.sol | 13 ++++ .../storageReturn/while_declaration_fine.sol | 25 +++++++ 26 files changed, 635 insertions(+) create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol new file mode 100644 index 000000000000..ddb5faa9fa2b --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol @@ -0,0 +1,38 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure { + S storage c; + assembly { + for {} eq(0,0) { c_slot := s_slot } {} + } + c; + } + function g() internal pure { + S storage c; + assembly { + for {} eq(0,1) { c_slot := s_slot } {} + } + c; + } + function h() internal pure { + S storage c; + assembly { + for {} eq(0,0) {} { c_slot := s_slot } + } + c; + } + function i() internal pure { + S storage c; + assembly { + for {} eq(0,1) {} { c_slot := s_slot } + } + c; + } +} +// ---- +// TypeError: (189-190): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (340-341): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (491-492): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (642-643): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. + diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol new file mode 100644 index 000000000000..19a58b2349bf --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol @@ -0,0 +1,19 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure { + S storage c; + assembly { + for { c_slot := s_slot } iszero(0) {} {} + } + c; + } + function g() internal pure { + S storage c; + assembly { + for { c_slot := s_slot } iszero(1) {} {} + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol new file mode 100644 index 000000000000..1d4302755f79 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol @@ -0,0 +1,13 @@ +contract C { + struct S { bool f; } + S s; + function f(bool flag) internal pure { + S storage c; + assembly { + if flag { c_slot := s_slot } + } + c; + } +} +// ---- +// TypeError: (188-189): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol new file mode 100644 index 000000000000..180feb770be2 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol @@ -0,0 +1,15 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure { + S storage c; + // this should warn about unreachable code, but currently function flow is ignored + assembly { + function f() { return(0, 0) } + f() + c_slot := s_slot + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol new file mode 100644 index 000000000000..bba9daf34627 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol @@ -0,0 +1,15 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure { + S storage c; + // this could be allowed, but currently control flow for functions is not analysed + assembly { + function f() { revert(0, 0) } + f() + } + c; + } +} +// ---- +// TypeError: (287-288): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol new file mode 100644 index 000000000000..c3f2409158ea --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol @@ -0,0 +1,12 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure { + S storage c; + assembly { + c_slot := s_slot + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol new file mode 100644 index 000000000000..72884e74159e --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol @@ -0,0 +1,33 @@ +contract C { + struct S { bool f; } + S s; + function f(uint256 a) internal pure { + S storage c; + assembly { + switch a + case 0 { c_slot := s_slot } + } + c; + } + function g(bool flag) internal pure { + S storage c; + assembly { + switch flag + case 0 { c_slot := s_slot } + case 1 { c_slot := s_slot } + } + c; + } + function h(uint256 a) internal pure { + S storage c; + assembly { + switch a + case 0 { c_slot := s_slot } + default { return(0,0) } + } + c; + } +} +// ---- +// TypeError: (208-209): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (421-422): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol new file mode 100644 index 000000000000..d723109244a6 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol @@ -0,0 +1,31 @@ +contract C { + struct S { bool f; } + S s; + function f(uint256 a) internal pure { + S storage c; + assembly { + switch a + default { c_slot := s_slot } + } + c; + } + function g(bool flag) internal pure { + S storage c; + assembly { + switch flag + case 0 { c_slot := s_slot } + default { c_slot := s_slot } + } + c; + } + function h(uint256 a) internal pure { + S storage c; + assembly { + switch a + case 0 { revert(0, 0) } + default { c_slot := s_slot } + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol new file mode 100644 index 000000000000..25654b1dda41 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol @@ -0,0 +1,66 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + do { + break; + c = s; + } while(false); + c; + } + function g() internal view { + S storage c; + do { + if (s.f) { + continue; + c = s; + } + else { + } + } while(false); + c; + } + function h() internal view { + S storage c; + do { + if (s.f) { + break; + } + else { + c = s; + } + } while(false); + c; + } + function i() internal view { + S storage c; + do { + if (s.f) { + continue; + } + else { + c = s; + } + } while(false); + c; + } + function j() internal view { + S storage c; + do { + continue; + c = s; + } while(false); + c; + } +} +// ---- +// TypeError: (184-185): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// Warning: (145-150): Unreachable code. +// Warning: (168-173): Unreachable code. +// TypeError: (411-412): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// Warning: (325-330): Unreachable code. +// TypeError: (635-636): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (862-863): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (1011-1012): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// Warning: (972-977): Unreachable code. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol new file mode 100644 index 000000000000..40ddc377773a --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol @@ -0,0 +1,44 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + do {} while((c = s).f); + c; + } + function g() internal view { + S storage c; + do { c = s; } while(false); + c; + } + function h() internal view { + S storage c; + c = s; + do {} while(false); + c; + } + function i() internal view { + S storage c; + do {} while(false); + c = s; + c; + } + function j() internal view { + S storage c; + do { + c = s; + break; + } while(false); + c; + } + function k() internal view { + S storage c; + do { + c = s; + continue; + } while(false); + c; + } +} +// ---- +// Warning: (606-611): Unreachable code. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol new file mode 100644 index 000000000000..e93d9798f215 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol @@ -0,0 +1,20 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + for(;; c = s) { + } + c; + } + function g() internal view { + S storage c; + for(;;) { + c = s; + } + c; + } +} +// ---- +//TypeError: (143-144): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (261-262): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol new file mode 100644 index 000000000000..b3e9f46d1468 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol @@ -0,0 +1,17 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + for(c = s;;) { + } + c; + } + function g() internal view { + S storage c; + for(; (c = s).f;) { + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol new file mode 100644 index 000000000000..7da6bef92e69 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol @@ -0,0 +1,22 @@ +contract C { + struct S { bool f; } + S s; + function f(bool flag) internal { + S storage c; + if (flag) c = s; + c; + } + function g(bool flag) internal { + S storage c; + if (flag) c = s; + else + { + if (!flag) c = s; + else s.f = true; + } + c; + } +} +// ---- +// TypeError: (138-139): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (330-331): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol new file mode 100644 index 000000000000..5d3a6d5bd52a --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol @@ -0,0 +1,39 @@ +contract C { + struct S { bool f; } + S s; + function f(bool flag) internal view { + S storage c; + if (flag) c = s; + else c = s; + c; + } + function g(bool flag) internal view { + S storage c; + if (flag) c = s; + else { c = s; } + c; + } + function h(bool flag) internal view { + S storage c; + if (flag) c = s; + else + { + if (!flag) c = s; + else c = s; + } + c; + } + function i() internal view { + S storage c; + if ((c = s).f) { + } + c; + } + function j() internal view { + S storage c; + if ((c = s).f && !(c = s).f) { + } + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol new file mode 100644 index 000000000000..6df4939cf4dc --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol @@ -0,0 +1,20 @@ +contract C { + modifier revertIfNoReturn() { + _; + revert(); + } + modifier ifFlag(bool flag) { + if (flag) + _; + } + struct S { uint a; } + S s; + function f(bool flag) revertIfNoReturn() internal view { + if (flag) s; + } + function g(bool flag) revertIfNoReturn() ifFlag(flag) internal view { + s; + } + +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol new file mode 100644 index 000000000000..5cb580528409 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol @@ -0,0 +1,11 @@ +contract C { + struct S { bool f; } + S s; + function g(bool flag) internal view { + S storage c; + if (flag) c = s; + else revert(); + s; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol new file mode 100644 index 000000000000..a6dd300cedad --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol @@ -0,0 +1,24 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + false && (c = s).f; + c; + } + function g() internal view { + S storage c; + true || (c = s).f; + c; + } + function h() internal view { + S storage c; + // expect error, although this is always fine + true && (false || (c = s).f); + c; + } +} +// ---- +// TypeError: (137-138): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (235-236): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (398-399): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol new file mode 100644 index 000000000000..e8ad5e4853f4 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol @@ -0,0 +1,15 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + (c = s).f && false; + c; + } + function g() internal view { + S storage c; + (c = s).f || true; + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol new file mode 100644 index 000000000000..f820456e18ee --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol @@ -0,0 +1,17 @@ +contract C { + struct S { bool f; } + S s; + function f() internal pure {} + function g() internal view { s; } + function h() internal view { + S storage c; + c = s; + c; + } + function i() internal view { + S storage c; + (c) = s; + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol new file mode 100644 index 000000000000..3b4552f86fef --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol @@ -0,0 +1,17 @@ +contract C { + struct S { bool f; } + S s; + function f(bool flag) internal view { + S storage c; + flag ? (c = s).f : false; + c; + } + function g(bool flag) internal view { + S storage c; + flag ? false : (c = s).f; + c; + } +} +// ---- +// TypeError: (152-153): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (266-267): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol new file mode 100644 index 000000000000..1dd8d2f5745e --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol @@ -0,0 +1,20 @@ +contract C { + struct S { bool f; } + S s; + function f(bool flag) internal view { + S storage c; + flag ? c = s : c = s; + c; + } + function g(bool flag) internal view { + S storage c; + flag ? c = s : (c = s); + c; + } + function h(bool flag) internal view { + S storage c; + flag ? (c = s).f : (c = s).f; + c; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol new file mode 100644 index 000000000000..ca43dc346fc6 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol @@ -0,0 +1,42 @@ +contract C { + struct S { bool f; } + S s; + function ext() external {} + function f() internal + { + S storage r; + try this.ext() { } + catch (bytes memory) { r = s; } + r; + } + function g() internal + { + S storage r; + try this.ext() { r = s; } + catch (bytes memory) { } + r; + } + function h() internal + { + S storage r; + try this.ext() {} + catch Error (string memory) { r = s; } + catch (bytes memory) { r = s; } + r; + } + function i() internal + { + S storage r; + try this.ext() { r = s; } + catch (bytes memory) { r; } + r = s; + r; + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// TypeError: (206-207): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (343-344): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (526-527): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. +// TypeError: (653-654): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol new file mode 100644 index 000000000000..6834525d5c01 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol @@ -0,0 +1,30 @@ +contract C { + struct S { bool f; } + S s; + function ext() external { } + function f() internal + { + S storage r; + try this.ext() { r = s; } + catch (bytes memory) { r = s; } + r; + } + function g() internal + { + S storage r; + try this.ext() { r = s; } + catch Error (string memory) { r = s; } + catch (bytes memory) { r = s; } + r; + } + function h() internal + { + S storage r; + try this.ext() { } + catch (bytes memory) { } + r = s; + r; + } +} +// ==== +// EVMVersion: >=byzantium diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol new file mode 100644 index 000000000000..e2e27419638a --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol @@ -0,0 +1,17 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view returns (S storage, uint) { + return (s,2); + } + function g() internal view { + uint a; + S storage c; + (c, a) = f(); + c; + } + function h() internal view { + (s, s); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol new file mode 100644 index 000000000000..cd6fee8dbfa8 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol @@ -0,0 +1,13 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + while(false) { + c = s; + } + c; + } +} +// ---- +// TypeError: (161-162): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol new file mode 100644 index 000000000000..20e72e5dbcb9 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol @@ -0,0 +1,25 @@ +contract C { + struct S { bool f; } + S s; + function f() internal view { + S storage c; + while((c = s).f) { + } + c; + } + function g() internal view { + S storage c; + c = s; + while(false) { + } + c; + } + function h() internal view { + S storage c; + while(false) { + } + c = s; + c; + } +} +// ---- From 8e6567e39926414d543f89bd6652019db60f1a51 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 2 Apr 2020 16:20:42 +0530 Subject: [PATCH 145/165] New folder localStorageVariable for new testcases; added two new tests --- .../assembly/for_declaration_err.sol | 0 .../assembly/for_declaration_fine.sol | 0 .../assembly/if_declaration_err.sol | 0 .../assembly/returning_function_declaration.sol | 0 .../assembly/reverting_function_declaration.sol | 0 .../assembly/stub_declaration.sol | 0 .../assembly/switch_declaration_err.sol | 0 .../assembly/switch_declaration_fine.sol | 0 .../dowhile_declaration_err.sol | 0 .../dowhile_declaration_fine.sol | 0 .../for_declaration_err.sol | 0 .../for_declaration_fine.sol | 0 .../if_declaration_err.sol | 0 .../if_declaration_fine.sol | 0 .../modifier_declaration_fine.sol | 0 .../revert_declaration_fine.sol | 0 .../short_circuit_declaration_err.sol | 0 .../short_circuit_declaration_fine.sol | 0 .../smoke_declaration.sol | 0 .../localStorageVariables/ternary_assignment_err.sol | 11 +++++++++++ .../localStorageVariables/ternary_assignment_fine.sol | 9 +++++++++ .../ternary_declaration_err.sol | 0 .../ternary_declaration_fine.sol | 0 .../try_declaration_err.sol | 0 .../try_declaration_fine.sol | 0 .../tuple_declaration_fine.sol | 0 .../while_declaration_err.sol | 0 .../while_declaration_fine.sol | 0 28 files changed, 20 insertions(+) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/for_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/for_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/if_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/returning_function_declaration.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/reverting_function_declaration.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/stub_declaration.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/switch_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/assembly/switch_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/dowhile_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/dowhile_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/for_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/for_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/if_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/if_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/modifier_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/revert_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/short_circuit_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/short_circuit_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/smoke_declaration.sol (100%) create mode 100644 test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_err.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_fine.sol rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/ternary_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/ternary_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/try_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/try_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/tuple_declaration_fine.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/while_declaration_err.sol (100%) rename test/libsolidity/syntaxTests/controlFlow/{storageReturn => localStorageVariables}/while_declaration_fine.sol (100%) diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/for_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/for_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/for_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/for_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/for_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/if_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/if_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/if_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/returning_function_declaration.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/returning_function_declaration.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/returning_function_declaration.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/reverting_function_declaration.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/reverting_function_declaration.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/reverting_function_declaration.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/stub_declaration.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/stub_declaration.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/stub_declaration.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/assembly/switch_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/assembly/switch_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/dowhile_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/dowhile_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/dowhile_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/dowhile_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/dowhile_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/for_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/for_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/for_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/for_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/for_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/if_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/if_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/if_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/if_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/if_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/revert_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/revert_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/revert_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/short_circuit_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/short_circuit_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/short_circuit_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/short_circuit_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/short_circuit_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/smoke_declaration.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/smoke_declaration.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/smoke_declaration.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_err.sol new file mode 100644 index 000000000000..2c47731aaceb --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_err.sol @@ -0,0 +1,11 @@ +contract C { + uint256[] s; + function f() public { + bool d; + uint256[] storage x; + uint256[] storage y = d ? (x = s) : x; + y; + } +} +// ---- +// TypeError: (145-146): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_fine.sol new file mode 100644 index 000000000000..a510bd40dada --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_assignment_fine.sol @@ -0,0 +1,9 @@ +contract C { + uint256[] s; + function f() public view { + uint256[] storage x; + uint256[] storage y = (x = s)[0] > 0 ? x : x; + y; + } +} +// --- diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/ternary_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/ternary_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/try_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/try_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/try_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/try_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/try_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/tuple_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/tuple_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/tuple_declaration_fine.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/while_declaration_err.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_err.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/while_declaration_err.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/while_declaration_fine.sol similarity index 100% rename from test/libsolidity/syntaxTests/controlFlow/storageReturn/while_declaration_fine.sol rename to test/libsolidity/syntaxTests/controlFlow/localStorageVariables/while_declaration_fine.sol From 9a8ca6ca33d9c9910f57c03690fd004e5ff95c1a Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Wed, 1 Apr 2020 12:24:08 +0200 Subject: [PATCH 146/165] Always return `this` for `EventDefinition::resolveVirtual` Instead of asserting. --- libsolidity/ast/AST.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 4bbacbdf3b90..3d64c828f7c4 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1039,7 +1039,7 @@ class EventDefinition: public CallableDeclaration, public StructurallyDocumented ContractDefinition const* ) const override { - solAssert(false, "Tried to resolve virtual event."); + return *this; } private: From ac7b31e5590fd4676b76afec878b838fe3c81abe Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 10 Mar 2020 18:15:50 +0100 Subject: [PATCH 147/165] Validate immutable variables --- Changelog.md | 1 + libsolidity/CMakeLists.txt | 2 + libsolidity/analysis/ImmutableValidator.cpp | 214 ++++++++++++++++++ libsolidity/analysis/ImmutableValidator.h | 78 +++++++ libsolidity/analysis/TypeChecker.cpp | 15 +- libsolidity/analysis/TypeChecker.h | 2 +- libsolidity/ast/AST.h | 18 ++ libsolidity/ast/ASTAnnotations.h | 3 + libsolidity/interface/CompilerStack.cpp | 10 + .../conditional_return_uninitialized.sol | 11 + .../immutable/conditionally_initialized.sol | 9 + .../ctor_indirect_initialization.sol | 12 + .../ctor_initialization_indirect_reading.sol | 10 + .../immutable/ctor_initialization_reading.sol | 8 + .../immutable/ctor_initialization_tuple.sol | 13 ++ .../immutable/ctor_modifier_args.sol | 12 + .../ctor_modifier_initialization.sol | 11 + .../immutable/ctor_modifier_reading.sol | 14 ++ .../syntaxTests/immutable/decrement.sol | 8 + .../syntaxTests/immutable/delete.sol | 8 + .../immutable/function_initialization.sol | 5 + .../function_initialization_reading.sol | 7 + .../function_pointer_initializing.sol | 14 ++ .../immutable/function_pointer_reading.sol | 13 ++ .../syntaxTests/immutable/getter.sol | 5 - .../syntaxTests/immutable/immutable_basic.sol | 4 +- .../syntaxTests/immutable/increment.sol | 8 + .../indirect_reading_during_statevar_init.sol | 8 + .../immutable/inheritance_ctor.sol | 15 ++ .../immutable/inheritance_ctor_argument.sol | 14 ++ ...e_ctor_inherit_specifier_argument_init.sol | 13 ++ ...tor_inherit_specifier_argument_reading.sol | 16 ++ .../inheritance_virtual_functions.sol | 19 ++ ...eritance_virtual_functions_direct_call.sol | 19 ++ .../inheritance_virtual_functions_super.sol | 19 ++ .../inheritance_virtual_modifiers.sol | 21 ++ .../immutable/inheritance_wrong_ctor.sol | 12 + .../immutable/initialized_after_ctor.sol | 8 + .../immutable/loop_initialized.sol | 9 + ...multiple_inheritance_virtual_functions.sol | 29 +++ ...heritance_virtual_functions_with_super.sol | 29 +++ .../immutable/multiple_initializations.sol | 9 + .../immutable/private_state_var.sol | 20 ++ .../reading_after_initialization.sol | 8 + .../reading_after_initialization_modifier.sol | 12 + .../reading_during_statevar_init.sol | 6 + .../immutable/return_uninitialized.sol | 10 + .../syntaxTests/immutable/selector.sol | 12 + .../immutable/selector_function_name.sol | 13 ++ .../immutable/selector_function_pointer.sol | 16 ++ .../syntaxTests/immutable/uninitialized.sol | 5 + .../uninitialized_private_state_var.sol | 21 ++ .../immutable/unrelated_reading.sol | 8 + .../writing_after_initialization.sol | 10 + .../writing_after_initialization_modifier.sol | 12 + .../syntaxTests/viewPureChecker/immutable.sol | 4 +- 56 files changed, 898 insertions(+), 14 deletions(-) create mode 100644 libsolidity/analysis/ImmutableValidator.cpp create mode 100644 libsolidity/analysis/ImmutableValidator.h create mode 100644 test/libsolidity/syntaxTests/immutable/conditional_return_uninitialized.sol create mode 100644 test/libsolidity/syntaxTests/immutable/conditionally_initialized.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_indirect_initialization.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_initialization_tuple.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_modifier_args.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_modifier_initialization.sol create mode 100644 test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/decrement.sol create mode 100644 test/libsolidity/syntaxTests/immutable/delete.sol create mode 100644 test/libsolidity/syntaxTests/immutable/function_initialization.sol create mode 100644 test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol create mode 100644 test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol delete mode 100644 test/libsolidity/syntaxTests/immutable/getter.sol create mode 100644 test/libsolidity/syntaxTests/immutable/increment.sol create mode 100644 test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_ctor.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_ctor_argument.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_init.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol create mode 100644 test/libsolidity/syntaxTests/immutable/inheritance_wrong_ctor.sol create mode 100644 test/libsolidity/syntaxTests/immutable/initialized_after_ctor.sol create mode 100644 test/libsolidity/syntaxTests/immutable/loop_initialized.sol create mode 100644 test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol create mode 100644 test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol create mode 100644 test/libsolidity/syntaxTests/immutable/multiple_initializations.sol create mode 100644 test/libsolidity/syntaxTests/immutable/private_state_var.sol create mode 100644 test/libsolidity/syntaxTests/immutable/reading_after_initialization.sol create mode 100644 test/libsolidity/syntaxTests/immutable/reading_after_initialization_modifier.sol create mode 100644 test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol create mode 100644 test/libsolidity/syntaxTests/immutable/return_uninitialized.sol create mode 100644 test/libsolidity/syntaxTests/immutable/selector.sol create mode 100644 test/libsolidity/syntaxTests/immutable/selector_function_name.sol create mode 100644 test/libsolidity/syntaxTests/immutable/selector_function_pointer.sol create mode 100644 test/libsolidity/syntaxTests/immutable/uninitialized.sol create mode 100644 test/libsolidity/syntaxTests/immutable/uninitialized_private_state_var.sol create mode 100644 test/libsolidity/syntaxTests/immutable/unrelated_reading.sol create mode 100644 test/libsolidity/syntaxTests/immutable/writing_after_initialization.sol create mode 100644 test/libsolidity/syntaxTests/immutable/writing_after_initialization_modifier.sol diff --git a/Changelog.md b/Changelog.md index f20b05aa54d9..6ca68ea85300 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Compiler Features: * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. * Commandline Interface: Enable output of storage layout with `--storage-layout`. + Bugfixes: * Inline Assembly: Fix internal error when accessing invalid constant variables. * Inline Assembly: Fix internal error when accessing functions. diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index ba2651e94e75..c7a517a0b911 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -14,6 +14,8 @@ set(sources analysis/DeclarationContainer.h analysis/DocStringAnalyser.cpp analysis/DocStringAnalyser.h + analysis/ImmutableValidator.cpp + analysis/ImmutableValidator.h analysis/GlobalContext.cpp analysis/GlobalContext.h analysis/NameAndTypeResolver.cpp diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp new file mode 100644 index 000000000000..e80902009c63 --- /dev/null +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -0,0 +1,214 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +#include + +using namespace solidity::frontend; + +void ImmutableValidator::analyze() +{ + m_inConstructionContext = true; + + auto linearizedContracts = m_currentContract.annotation().linearizedBaseContracts | boost::adaptors::reversed; + + for (ContractDefinition const* contract: linearizedContracts) + for (VariableDeclaration const* stateVar: contract->stateVariables()) + if (stateVar->value()) + { + stateVar->value()->accept(*this); + solAssert(m_initializedStateVariables.emplace(stateVar).second, ""); + } + + for (ContractDefinition const* contract: linearizedContracts) + if (contract->constructor()) + visitCallableIfNew(*contract->constructor()); + + for (ContractDefinition const* contract: linearizedContracts) + for (std::shared_ptr const inheritSpec: contract->baseContracts()) + if (auto args = inheritSpec->arguments()) + ASTNode::listAccept(*args, *this); + + m_inConstructionContext = false; + + for (ContractDefinition const* contract: linearizedContracts) + { + for (auto funcDef: contract->definedFunctions()) + visitCallableIfNew(*funcDef); + + for (auto modDef: contract->functionModifiers()) + visitCallableIfNew(*modDef); + } + + checkAllVariablesInitialized(m_currentContract.location()); +} + +bool ImmutableValidator::visit(FunctionDefinition const& _functionDefinition) +{ + return analyseCallable(_functionDefinition); +} + +bool ImmutableValidator::visit(ModifierDefinition const& _modifierDefinition) +{ + return analyseCallable(_modifierDefinition); +} + +bool ImmutableValidator::visit(MemberAccess const& _memberAccess) +{ + _memberAccess.expression().accept(*this); + + if (auto varDecl = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + analyseVariableReference(*varDecl, _memberAccess); + else if (auto funcType = dynamic_cast(_memberAccess.annotation().type)) + if (funcType->kind() == FunctionType::Kind::Internal && funcType->hasDeclaration()) + visitCallableIfNew(funcType->declaration()); + + return false; +} + +bool ImmutableValidator::visit(IfStatement const& _ifStatement) +{ + bool prevInBranch = m_inBranch; + + _ifStatement.condition().accept(*this); + + m_inBranch = true; + _ifStatement.trueStatement().accept(*this); + + if (auto falseStatement = _ifStatement.falseStatement()) + falseStatement->accept(*this); + + m_inBranch = prevInBranch; + + return false; +} + +bool ImmutableValidator::visit(WhileStatement const& _whileStatement) +{ + bool prevInLoop = m_inLoop; + m_inLoop = true; + + _whileStatement.condition().accept(*this); + _whileStatement.body().accept(*this); + + m_inLoop = prevInLoop; + + return false; +} + +void ImmutableValidator::endVisit(Identifier const& _identifier) +{ + if (auto const callableDef = dynamic_cast(_identifier.annotation().referencedDeclaration)) + visitCallableIfNew(callableDef->resolveVirtual(m_currentContract)); + if (auto const varDecl = dynamic_cast(_identifier.annotation().referencedDeclaration)) + analyseVariableReference(*varDecl, _identifier); +} + +void ImmutableValidator::endVisit(Return const& _return) +{ + if (m_currentConstructor != nullptr) + checkAllVariablesInitialized(_return.location()); +} + +bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDeclaration) +{ + FunctionDefinition const* prevConstructor = m_currentConstructor; + m_currentConstructor = nullptr; + + if (FunctionDefinition const* funcDef = dynamic_cast(&_callableDeclaration)) + { + ASTNode::listAccept(funcDef->modifiers(), *this); + + if (funcDef->isConstructor()) + m_currentConstructor = funcDef; + + if (funcDef->isImplemented()) + funcDef->body().accept(*this); + } + else if (ModifierDefinition const* modDef = dynamic_cast(&_callableDeclaration)) + modDef->body().accept(*this); + + m_currentConstructor = prevConstructor; + + return false; +} + +void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _variableReference, Expression const& _expression) +{ + if (!_variableReference.isStateVariable() || !_variableReference.immutable()) + return; + + if (_expression.annotation().lValueRequested && _expression.annotation().lValueOfOrdinaryAssignment) + { + if (!m_currentConstructor) + m_errorReporter.typeError( + _expression.location(), + "Immutable variables can only be initialized inline or assigned directly in the constructor." + ); + else if (m_currentConstructor->annotation().contract->id() != _variableReference.annotation().contract->id()) + m_errorReporter.typeError( + _expression.location(), + "Immutable variables must be initialized in the constructor of the contract they are defined in." + ); + else if (m_inLoop) + m_errorReporter.typeError( + _expression.location(), + "Immutable variables can only be initialized once, not in a while statement." + ); + else if (m_inBranch) + m_errorReporter.typeError( + _expression.location(), + "Immutable variables must be initialized unconditionally, not in an if statement." + ); + + if (!m_initializedStateVariables.emplace(&_variableReference).second) + m_errorReporter.typeError( + _expression.location(), + "Immutable state variable already initialized." + ); + } + else if (m_inConstructionContext) + m_errorReporter.typeError( + _expression.location(), + "Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it." + ); +} + +void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::SourceLocation const& _location) +{ + for (ContractDefinition const* contract: m_currentContract.annotation().linearizedBaseContracts) + for (VariableDeclaration const* varDecl: contract->stateVariables()) + if (varDecl->immutable()) + if (!util::contains(m_initializedStateVariables, varDecl)) + m_errorReporter.typeError( + _location, + solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()), + "Construction control flow ends without initializing all immutable state variables." + ); +} + +void ImmutableValidator::visitCallableIfNew(Declaration const& _declaration) +{ + CallableDeclaration const* _callable = dynamic_cast(&_declaration); + solAssert(_callable != nullptr, ""); + + if (m_visitedCallables.emplace(_callable).second) + _declaration.accept(*this); +} diff --git a/libsolidity/analysis/ImmutableValidator.h b/libsolidity/analysis/ImmutableValidator.h new file mode 100644 index 000000000000..5845ba011afd --- /dev/null +++ b/libsolidity/analysis/ImmutableValidator.h @@ -0,0 +1,78 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#pragma once + +#include +#include + +#include + +namespace solidity::frontend +{ + +/** + * Validates access and initialization of immutable variables: + * must be directly initialized in their respective c'tor + * can not be read by any function/modifier called by the c'tor (or the c'tor itself) + * must be initialized outside loops (only one initialization) + * must be initialized outside ifs (must be initialized unconditionally) + * must be initialized exactly once (no multiple statements) + * must be initialized exactly once (no early return to skip initialization) +*/ +class ImmutableValidator: private ASTConstVisitor +{ + using CallableDeclarationSet = std::set; + +public: + ImmutableValidator(langutil::ErrorReporter& _errorReporter, ContractDefinition const& _contractDefinition): + m_currentContract(_contractDefinition), + m_errorReporter(_errorReporter) + { } + + void analyze(); + +private: + bool visit(FunctionDefinition const& _functionDefinition); + bool visit(ModifierDefinition const& _modifierDefinition); + bool visit(MemberAccess const& _memberAccess); + bool visit(IfStatement const& _ifStatement); + bool visit(WhileStatement const& _whileStatement); + void endVisit(Identifier const& _identifier); + void endVisit(Return const& _return); + + bool analyseCallable(CallableDeclaration const& _callableDeclaration); + void analyseVariableReference(VariableDeclaration const& _variableReference, Expression const& _expression); + + void checkAllVariablesInitialized(langutil::SourceLocation const& _location); + + void visitCallableIfNew(Declaration const& _declaration); + + ContractDefinition const& m_currentContract; + + CallableDeclarationSet m_visitedCallables; + + std::set m_initializedStateVariables; + langutil::ErrorReporter& m_errorReporter; + + FunctionDefinition const* m_currentConstructor = nullptr; + bool m_inLoop = false; + bool m_inBranch = false; + bool m_inConstructionContext = false; +}; + +} diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index e6a2408f15b7..8e7bef338d6e 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1337,7 +1337,10 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& bool TypeChecker::visit(Assignment const& _assignment) { - requireLValue(_assignment.leftHandSide()); + requireLValue( + _assignment.leftHandSide(), + _assignment.assignmentOperator() == Token::Assign + ); TypePointer t = type(_assignment.leftHandSide()); _assignment.annotation().type = t; @@ -1395,7 +1398,10 @@ bool TypeChecker::visit(TupleExpression const& _tuple) for (auto const& component: components) if (component) { - requireLValue(*component); + requireLValue( + *component, + _tuple.annotation().lValueOfOrdinaryAssignment + ); types.push_back(type(*component)); } else @@ -1480,7 +1486,7 @@ bool TypeChecker::visit(UnaryOperation const& _operation) Token op = _operation.getOperator(); bool const modifying = (op == Token::Inc || op == Token::Dec || op == Token::Delete); if (modifying) - requireLValue(_operation.subExpression()); + requireLValue(_operation.subExpression(), false); else _operation.subExpression().accept(*this); TypePointer const& subExprType = type(_operation.subExpression()); @@ -2988,9 +2994,10 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte return true; } -void TypeChecker::requireLValue(Expression const& _expression) +void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAssignment) { _expression.annotation().lValueRequested = true; + _expression.annotation().lValueOfOrdinaryAssignment = _ordinaryAssignment; _expression.accept(*this); if (_expression.annotation().isLValue) diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index d428a6ac9754..a26ab81bdcfa 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -158,7 +158,7 @@ class TypeChecker: private ASTConstVisitor /// convertible to @a _expectedType. bool expectType(Expression const& _expression, Type const& _expectedType); /// Runs type checks on @a _expression to infer its type and then checks that it is an LValue. - void requireLValue(Expression const& _expression); + void requireLValue(Expression const& _expression, bool _ordinaryAssignment); ContractDefinition const* m_scope = nullptr; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 3d64c828f7c4..4979d5d4eec6 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -62,6 +62,24 @@ class ASTConstVisitor; class ASTNode: private boost::noncopyable { public: + struct CompareByID + { + using is_transparent = void; + + bool operator()(ASTNode const* _lhs, ASTNode const* _rhs) const + { + return _lhs->id() < _rhs->id(); + } + bool operator()(ASTNode const* _lhs, int64_t _rhs) const + { + return _lhs->id() < _rhs; + } + bool operator()(int64_t _lhs, ASTNode const* _rhs) const + { + return _lhs < _rhs->id(); + } + }; + using SourceLocation = langutil::SourceLocation; explicit ASTNode(int64_t _id, SourceLocation const& _location); diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 86636684c159..a724472d0224 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -208,6 +208,9 @@ struct ExpressionAnnotation: ASTAnnotation bool isLValue = false; /// Whether the expression is used in a context where the LValue is actually required. bool lValueRequested = false; + /// Whether the expression is an lvalue that is only assigned. + /// Would be false for --, ++, delete, +=, -=, .... + bool lValueOfOrdinaryAssignment = false; /// Types and - if given - names of arguments if the expr. is a function /// that is called, used for overload resoultion diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 781f68d6b185..fe0268fb1aa0 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -383,6 +384,15 @@ bool CompilerStack::analyze() noErrors = false; } + // Check that immutable variables are never read in c'tors and assigned + // exactly once + if (noErrors) + for (Source const* source: m_sourceOrder) + if (source->ast) + for (ASTPointer const& node: source->ast->nodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + ImmutableValidator(m_errorReporter, *contract).analyze(); + if (noErrors) { // Control flow graph generator and analyzer. It can check for issues such as diff --git a/test/libsolidity/syntaxTests/immutable/conditional_return_uninitialized.sol b/test/libsolidity/syntaxTests/immutable/conditional_return_uninitialized.sol new file mode 100644 index 000000000000..702f0307981d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/conditional_return_uninitialized.sol @@ -0,0 +1,11 @@ +contract C { + uint immutable x; + constructor() public { + if (false) + return; + + x = 1; + } +} +// ---- +// TypeError: (93-100): Construction control flow ends without initializing all immutable state variables. diff --git a/test/libsolidity/syntaxTests/immutable/conditionally_initialized.sol b/test/libsolidity/syntaxTests/immutable/conditionally_initialized.sol new file mode 100644 index 000000000000..b8557321b9ef --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/conditionally_initialized.sol @@ -0,0 +1,9 @@ +contract C { + uint immutable x; + constructor() public { + if (false) + x = 1; + } +} +// ---- +// TypeError: (93-94): Immutable variables must be initialized unconditionally, not in an if statement. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_indirect_initialization.sol b/test/libsolidity/syntaxTests/immutable/ctor_indirect_initialization.sol new file mode 100644 index 000000000000..1423659c8912 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_indirect_initialization.sol @@ -0,0 +1,12 @@ +contract C { + uint immutable x; + constructor() public { + initX(); + } + + function initX() internal { + x = 3; + } +} +// ---- +// TypeError: (126-127): Immutable variables can only be initialized inline or assigned directly in the constructor. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol new file mode 100644 index 000000000000..ad17635c4311 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_initialization_indirect_reading.sol @@ -0,0 +1,10 @@ +contract C { + uint immutable x; + constructor() public { + x = f(); + } + + function f() public pure returns (uint) { return 3 + x; } +} +// ---- +// TypeError: (143-144): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol new file mode 100644 index 000000000000..0b2207808434 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_initialization_reading.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x; + constructor() public { + x = 3 + x; + } +} +// ---- +// TypeError: (78-79): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_initialization_tuple.sol b/test/libsolidity/syntaxTests/immutable/ctor_initialization_tuple.sol new file mode 100644 index 000000000000..f3b724f0324a --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_initialization_tuple.sol @@ -0,0 +1,13 @@ +contract C { + uint immutable x; + uint immutable y; + constructor() public { + (x, y) = f(); + } + + function f() internal pure returns(uint _x, uint _y) { + _x = 3; + _y = 4; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/immutable/ctor_modifier_args.sol b/test/libsolidity/syntaxTests/immutable/ctor_modifier_args.sol new file mode 100644 index 000000000000..2c1c37c79b22 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_modifier_args.sol @@ -0,0 +1,12 @@ +contract C { + uint immutable x; + constructor() readX(x = 3) public { } + + modifier readX(uint _x) { + _; f(_x); + } + + function f(uint a) internal pure {} +} +// ---- +// TypeError: (59-60): Immutable variables can only be initialized inline or assigned directly in the constructor. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_modifier_initialization.sol b/test/libsolidity/syntaxTests/immutable/ctor_modifier_initialization.sol new file mode 100644 index 000000000000..b266665308bc --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_modifier_initialization.sol @@ -0,0 +1,11 @@ +contract C { + uint immutable x; + constructor() initX public { + } + + modifier initX() { + _; x = 23; + } +} +// ---- +// TypeError: (109-110): Immutable variables can only be initialized inline or assigned directly in the constructor. diff --git a/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol b/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol new file mode 100644 index 000000000000..a9a1b3a225e5 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/ctor_modifier_reading.sol @@ -0,0 +1,14 @@ +contract C { + uint immutable x; + constructor() readX public { + x = 3; + } + + modifier readX() { + _; f(x); + } + + function f(uint a) internal pure {} +} +// ---- +// TypeError: (126-127): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/decrement.sol b/test/libsolidity/syntaxTests/immutable/decrement.sol new file mode 100644 index 000000000000..54ac9f6158da --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/decrement.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 3; + constructor() public { + x--; + } +} +// ---- +// TypeError: (74-75): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/delete.sol b/test/libsolidity/syntaxTests/immutable/delete.sol new file mode 100644 index 000000000000..def28fad2814 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/delete.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 3; + constructor() public { + delete x; + } +} +// ---- +// TypeError: (81-82): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/function_initialization.sol b/test/libsolidity/syntaxTests/immutable/function_initialization.sol new file mode 100644 index 000000000000..c836beb27b08 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/function_initialization.sol @@ -0,0 +1,5 @@ +contract C { + uint immutable x = f(); + + function f() public pure returns (uint) { return 3; } +} diff --git a/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol b/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol new file mode 100644 index 000000000000..2a4365e69ffe --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/function_initialization_reading.sol @@ -0,0 +1,7 @@ +contract C { + uint immutable x = f(); + + function f() public pure returns (uint) { return 3 + x; } +} +// ---- +// TypeError: (99-100): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol b/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol new file mode 100644 index 000000000000..04eaa621ddec --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/function_pointer_initializing.sol @@ -0,0 +1,14 @@ +contract B { + uint immutable x; + + constructor(function() internal returns(uint) fp) internal { + x = fp(); + } +} + +contract C is B(C.f) { + function f() internal returns(uint) { return x = 2; } +} +// ---- +// TypeError: (200-201): Immutable variables can only be initialized inline or assigned directly in the constructor. +// TypeError: (200-201): Immutable state variable already initialized. diff --git a/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol b/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol new file mode 100644 index 000000000000..2ec62e93102b --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/function_pointer_reading.sol @@ -0,0 +1,13 @@ +contract B { + uint immutable x; + + constructor(function() internal returns(uint) fp) internal { + x = fp(); + } +} + +contract C is B(C.f) { + function f() internal returns(uint) { return x + 2; } +} +// ---- +// TypeError: (200-201): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/getter.sol b/test/libsolidity/syntaxTests/immutable/getter.sol deleted file mode 100644 index 7740f86430f9..000000000000 --- a/test/libsolidity/syntaxTests/immutable/getter.sol +++ /dev/null @@ -1,5 +0,0 @@ -contract C { - uint immutable public x; -} -// ---- -// UnimplementedFeatureError: NONE diff --git a/test/libsolidity/syntaxTests/immutable/immutable_basic.sol b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol index b4960f25b9a0..3d8e04636279 100644 --- a/test/libsolidity/syntaxTests/immutable/immutable_basic.sol +++ b/test/libsolidity/syntaxTests/immutable/immutable_basic.sol @@ -1,3 +1,3 @@ contract C { - uint immutable x; -} \ No newline at end of file + uint immutable x = 0; +} diff --git a/test/libsolidity/syntaxTests/immutable/increment.sol b/test/libsolidity/syntaxTests/immutable/increment.sol new file mode 100644 index 000000000000..0068bf87d77d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/increment.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 3; + constructor() public { + x++; + } +} +// ---- +// TypeError: (74-75): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol b/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol new file mode 100644 index 000000000000..5f659bff6a08 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/indirect_reading_during_statevar_init.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 0; + uint y = f(); + + function f() internal returns(uint) { return x; } +} +// ---- +// TypeError: (107-108): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_ctor.sol b/test/libsolidity/syntaxTests/immutable/inheritance_ctor.sol new file mode 100644 index 000000000000..ee794fd37156 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_ctor.sol @@ -0,0 +1,15 @@ +contract B { + uint immutable x; + + constructor() public { + x = 3; + } +} + +contract C is B { + uint immutable y; + constructor() public { + y = 3; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_ctor_argument.sol b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_argument.sol new file mode 100644 index 000000000000..0d98f8b40122 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_argument.sol @@ -0,0 +1,14 @@ +contract B { + uint immutable x; + + constructor(uint _x) public { + x = _x; + } +} + +contract C is B { + uint immutable y; + constructor() B(y = 3) public { } +} +// ---- +// TypeError: (155-156): Immutable variables can only be initialized inline or assigned directly in the constructor. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_init.sol b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_init.sol new file mode 100644 index 000000000000..16ed52f36bef --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_init.sol @@ -0,0 +1,13 @@ +contract B { + uint immutable x; + + constructor(uint _x) public { + x = _x; + } +} + +contract C is B(C.y = 3) { + uint immutable y; +} +// ---- +// TypeError: (111-114): Immutable variables can only be initialized inline or assigned directly in the constructor. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol new file mode 100644 index 000000000000..ed352746f7f3 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_ctor_inherit_specifier_argument_reading.sol @@ -0,0 +1,16 @@ +contract B { + uint immutable x; + + constructor(uint _x) public { + x = _x; + } +} + +contract C is B(C.y) { + uint immutable y; + constructor() public { + y = 3; + } +} +// ---- +// TypeError: (111-114): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol new file mode 100644 index 000000000000..d56fb487ad44 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions.sol @@ -0,0 +1,19 @@ +contract B { + uint immutable x; + + constructor() public { + x = xInit(); + } + + function xInit() internal virtual returns(uint) { + return 3; + } +} + +contract C is B { + function xInit() internal override returns(uint) { + return x; + } +} +// ---- +// TypeError: (260-261): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol new file mode 100644 index 000000000000..5dda6bfb00dd --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_direct_call.sol @@ -0,0 +1,19 @@ +contract B { + uint immutable x = 3; + + function readX() internal virtual returns(uint) { + return x; + } +} + +contract C is B { + constructor() public { + B.readX; + } + + function readX() internal override returns(uint) { + return 3; + } +} +// ---- +// TypeError: (109-110): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol new file mode 100644 index 000000000000..278efe55ff45 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_functions_super.sol @@ -0,0 +1,19 @@ +contract B { + uint immutable x = 3; + + function readX() internal view virtual returns(uint) { + return x; + } +} + +contract C is B { + constructor() public { + super.readX(); + } + + function readX() internal view override returns(uint) { + return 1; + } +} +// ---- +// TypeError: (114-115): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol new file mode 100644 index 000000000000..f1e60dbd822d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_virtual_modifiers.sol @@ -0,0 +1,21 @@ +contract B { + uint immutable x; + + constructor() readX public { + x = 3; + } + + modifier readX() virtual { + _; f(3); + } + + function f(uint a) internal pure {} +} + +contract C is B { + modifier readX() override { + _; f(x); + } +} +// ---- +// TypeError: (252-253): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/inheritance_wrong_ctor.sol b/test/libsolidity/syntaxTests/immutable/inheritance_wrong_ctor.sol new file mode 100644 index 000000000000..24a5239ed849 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/inheritance_wrong_ctor.sol @@ -0,0 +1,12 @@ +contract B { + uint immutable x = 4; +} + +contract C is B { + constructor() public { + x = 3; + } +} +// ---- +// TypeError: (95-96): Immutable variables must be initialized in the constructor of the contract they are defined in. +// TypeError: (95-96): Immutable state variable already initialized. diff --git a/test/libsolidity/syntaxTests/immutable/initialized_after_ctor.sol b/test/libsolidity/syntaxTests/immutable/initialized_after_ctor.sol new file mode 100644 index 000000000000..a6db6a6650da --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/initialized_after_ctor.sol @@ -0,0 +1,8 @@ +contract C { + constructor() public { + return; + } + + uint immutable x = 3; +} +// ---- diff --git a/test/libsolidity/syntaxTests/immutable/loop_initialized.sol b/test/libsolidity/syntaxTests/immutable/loop_initialized.sol new file mode 100644 index 000000000000..2827ab38972d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/loop_initialized.sol @@ -0,0 +1,9 @@ +contract C { + uint immutable x; + constructor() public { + while (true) + x = 1; + } +} +// ---- +// TypeError: (95-96): Immutable variables can only be initialized once, not in a while statement. diff --git a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol new file mode 100644 index 000000000000..c71335b839ad --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions.sol @@ -0,0 +1,29 @@ +contract A { + function f() internal virtual returns(uint) { return 3; } +} + +contract B { + uint immutable x; + + constructor() public { + x = xInit(); + } + + function xInit() internal virtual returns(uint) { + return f(); + } + + function f() internal virtual returns(uint) { return 3; } +} + +contract C is A, B { + function xInit() internal override returns(uint) { + return B.xInit(); + } + + function f() internal override(A, B) returns(uint) { + return x; + } +} +// ---- +// TypeError: (496-497): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol new file mode 100644 index 000000000000..eaabbb71a261 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/multiple_inheritance_virtual_functions_with_super.sol @@ -0,0 +1,29 @@ +contract A { + function f() internal virtual returns(uint) { return 3; } +} + +contract B { + uint immutable x; + + constructor() public { + x = xInit(); + } + + function xInit() internal virtual returns(uint) { + return f(); + } + + function f() internal virtual returns(uint) { return 3; } +} + +contract C is A, B { + function xInit() internal override returns(uint) { + return super.xInit(); + } + + function f() internal override(A, B) returns(uint) { + return x; + } +} +// ---- +// TypeError: (500-501): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/multiple_initializations.sol b/test/libsolidity/syntaxTests/immutable/multiple_initializations.sol new file mode 100644 index 000000000000..8ff940fefe00 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/multiple_initializations.sol @@ -0,0 +1,9 @@ +contract C { + uint immutable x; + constructor() public { + x = 1; + x = 4; + } +} +// ---- +// TypeError: (85-86): Immutable state variable already initialized. diff --git a/test/libsolidity/syntaxTests/immutable/private_state_var.sol b/test/libsolidity/syntaxTests/immutable/private_state_var.sol new file mode 100644 index 000000000000..2cfc22a85317 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/private_state_var.sol @@ -0,0 +1,20 @@ +contract B { + uint immutable private x = f(); + + constructor() public { + } + + function f() internal view virtual returns(uint) { return 1; } + function readX() internal view returns(uint) { return x; } +} + +contract C is B { + uint immutable y; + constructor() public { + y = 3; + } + function f() internal view override returns(uint) { return readX(); } + +} +// ---- +// TypeError: (209-210): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/reading_after_initialization.sol b/test/libsolidity/syntaxTests/immutable/reading_after_initialization.sol new file mode 100644 index 000000000000..b64f236a972b --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/reading_after_initialization.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 0; + uint y = 0; + + function f() internal { + y = x + 1; + } +} diff --git a/test/libsolidity/syntaxTests/immutable/reading_after_initialization_modifier.sol b/test/libsolidity/syntaxTests/immutable/reading_after_initialization_modifier.sol new file mode 100644 index 000000000000..4de778ba3e74 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/reading_after_initialization_modifier.sol @@ -0,0 +1,12 @@ +contract C { + uint immutable x = 0; + uint y = 0; + + function f() readX internal { + } + + modifier readX() { + _; + y = x + 1; + } +} diff --git a/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol b/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol new file mode 100644 index 000000000000..d35c68d8a863 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/reading_during_statevar_init.sol @@ -0,0 +1,6 @@ +contract C { + uint immutable x = 0; + uint y = x; +} +// ---- +// TypeError: (52-53): Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it. diff --git a/test/libsolidity/syntaxTests/immutable/return_uninitialized.sol b/test/libsolidity/syntaxTests/immutable/return_uninitialized.sol new file mode 100644 index 000000000000..0fd5461d4b3d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/return_uninitialized.sol @@ -0,0 +1,10 @@ +contract C { + uint immutable x; + constructor() public { + return; + + x = 1; + } +} +// ---- +// TypeError: (70-77): Construction control flow ends without initializing all immutable state variables. diff --git a/test/libsolidity/syntaxTests/immutable/selector.sol b/test/libsolidity/syntaxTests/immutable/selector.sol new file mode 100644 index 000000000000..4b880c8e8bcb --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/selector.sol @@ -0,0 +1,12 @@ +contract C { + uint immutable x; + constructor() public { + x = 3; + this.readX.selector; + } + + function readX() external view returns(uint) { return x; } +} +// ---- +// Warning: (85-104): Statement has no effect. +// Warning: (85-89): "this" used in constructor. Note that external functions of a contract cannot be called while it is being constructed. diff --git a/test/libsolidity/syntaxTests/immutable/selector_function_name.sol b/test/libsolidity/syntaxTests/immutable/selector_function_name.sol new file mode 100644 index 000000000000..c84f724089e2 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/selector_function_name.sol @@ -0,0 +1,13 @@ +contract C { + uint immutable x; + constructor() public { + x = 3; + C.selector.selector; + C.selector; + } + + function selector() external view returns(uint) { return x; } +} +// ---- +// Warning: (85-104): Statement has no effect. +// Warning: (114-124): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/immutable/selector_function_pointer.sol b/test/libsolidity/syntaxTests/immutable/selector_function_pointer.sol new file mode 100644 index 000000000000..a8b91a639349 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/selector_function_pointer.sol @@ -0,0 +1,16 @@ +contract C { + uint immutable x; + constructor() public { + x = 3; + readX().selector; + } + + function f() external view returns(uint) { + return x; + } + + function readX() public view returns(function() external view returns(uint) _f) { + _f = this.f; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/immutable/uninitialized.sol b/test/libsolidity/syntaxTests/immutable/uninitialized.sol new file mode 100644 index 000000000000..18c60ea9df3d --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/uninitialized.sol @@ -0,0 +1,5 @@ +contract C { + uint immutable x; +} +// ---- +// TypeError: (0-36): Construction control flow ends without initializing all immutable state variables. diff --git a/test/libsolidity/syntaxTests/immutable/uninitialized_private_state_var.sol b/test/libsolidity/syntaxTests/immutable/uninitialized_private_state_var.sol new file mode 100644 index 000000000000..69aa5448f542 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/uninitialized_private_state_var.sol @@ -0,0 +1,21 @@ +contract B { + uint immutable private x; + + constructor() public { + } + + function f() internal view virtual returns(uint) { return 1; } + function readX() internal view returns(uint) { return x; } +} + +contract C is B { + uint immutable y; + constructor() public { + y = 3; + } + function f() internal view override returns(uint) { return readX(); } + +} +// ---- +// TypeError: (0-209): Construction control flow ends without initializing all immutable state variables. +// TypeError: (211-375): Construction control flow ends without initializing all immutable state variables. diff --git a/test/libsolidity/syntaxTests/immutable/unrelated_reading.sol b/test/libsolidity/syntaxTests/immutable/unrelated_reading.sol new file mode 100644 index 000000000000..2b5614650666 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/unrelated_reading.sol @@ -0,0 +1,8 @@ +contract C { + uint immutable x = 1; + + function readX() internal view returns(uint) { + return x + 3; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/immutable/writing_after_initialization.sol b/test/libsolidity/syntaxTests/immutable/writing_after_initialization.sol new file mode 100644 index 000000000000..e844de0800fc --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/writing_after_initialization.sol @@ -0,0 +1,10 @@ +contract C { + uint immutable x = 0; + + function f() internal { + x = 1; + } +} +// ---- +// TypeError: (76-77): Immutable variables can only be initialized inline or assigned directly in the constructor. +// TypeError: (76-77): Immutable state variable already initialized. diff --git a/test/libsolidity/syntaxTests/immutable/writing_after_initialization_modifier.sol b/test/libsolidity/syntaxTests/immutable/writing_after_initialization_modifier.sol new file mode 100644 index 000000000000..592633379c84 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/writing_after_initialization_modifier.sol @@ -0,0 +1,12 @@ +contract C { + uint immutable x = 0; + + function f() readX internal { } + + modifier readX() { + _; x = 1; + } +} +// ---- +// TypeError: (111-112): Immutable variables can only be initialized inline or assigned directly in the constructor. +// TypeError: (111-112): Immutable state variable already initialized. diff --git a/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol index 1c0e7a46f0ef..9028c7ccc8bc 100644 --- a/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol +++ b/test/libsolidity/syntaxTests/viewPureChecker/immutable.sol @@ -1,8 +1,8 @@ contract B { - uint immutable x; + uint immutable x = 1; function f() public pure returns (uint) { return x; } } // ---- -// TypeError: (96-97): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". +// TypeError: (100-101): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view". From cb66274827d83236632ba648816323299bbdc8ec Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 2 Apr 2020 17:33:35 +0530 Subject: [PATCH 148/165] Added changelog --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index f20b05aa54d9..05b3fa8c18f9 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Important Bugfixes: Language Features: + * Allow local storage variables to be declared without initialization, as long as they are assigned before they are accessed. Compiler Features: From a7e1ef6a5060d1963d67db4a47e9c17579b7338a Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Wed, 1 Apr 2020 19:11:03 -0500 Subject: [PATCH 149/165] [build-system] Add -Wpessimizing-move & -Wredundant-move warnings. -Wpessimizing-move warns when a call to std::move would prevent copy elision if the argument was not wrapped in a call. This happens when moving a local variable in a return statement when the variable is the same type as the return type or using a move to create a new object from a temporary object. -Wredundant-move warns when an implicit move would already be made, so the std::move call is not needed, such as when moving a local variable in a return that is different from the return type. --- cmake/EthCompilerSettings.cmake | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index cc4489e9faee..b36af7e3f8ed 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -26,6 +26,17 @@ eth_add_cxx_compiler_flag_if_supported(-Wimplicit-fallthrough) # Prevent the path of the source directory from ending up in the binary via __FILE__ macros. eth_add_cxx_compiler_flag_if_supported("-fmacro-prefix-map=${CMAKE_SOURCE_DIR}=/solidity") +# -Wpessimizing-move warns when a call to std::move would prevent copy elision +# if the argument was not wrapped in a call. This happens when moving a local +# variable in a return statement when the variable is the same type as the +# return type or using a move to create a new object from a temporary object. +eth_add_cxx_compiler_flag_if_supported(-Wpessimizing-move) + +# -Wredundant-move warns when an implicit move would already be made, so the +# std::move call is not needed, such as when moving a local variable in a return +# that is different from the return type. +eth_add_cxx_compiler_flag_if_supported(-Wredundant-move) + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) # Enables all the warnings about constructions that some users consider questionable, # and that are easy to avoid. Also enable some extra warning flags that are not From 39ff0deb051a5dfc2c2d2403d4f580d31d9bcea9 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 2 Mar 2020 21:42:46 +0100 Subject: [PATCH 150/165] Zero initialize memory arrays --- libsolidity/ast/Types.cpp | 2 +- libsolidity/codegen/YulUtilFunctions.cpp | 170 +++++++++++++++--- libsolidity/codegen/YulUtilFunctions.h | 28 ++- .../codegen/ir/IRGenerationContext.cpp | 6 +- libsolidity/codegen/ir/IRGenerator.cpp | 13 ++ libsolidity/codegen/ir/IRGenerator.h | 3 + .../codegen/ir/IRGeneratorForStatements.cpp | 35 +++- .../codegen/ir/IRGeneratorForStatements.h | 7 + .../standard_ir_requested/output.json | 2 + .../yul_string_format_ascii/output.json | 14 ++ .../output.json | 14 ++ .../output.json | 14 ++ .../yul_string_format_ascii_long/output.json | 14 ++ .../yul_string_format_hex/output.json | 14 ++ .../viaYul/array_function_pointers.sol | 29 +++ .../array_2d_zeroed_memory_index_access.sol | 24 +++ .../array_array_static.sol | 22 +++ ...eturn_param_zeroed_memory_index_access.sol | 17 ++ ...rray_static_zeroed_memory_index_access.sol | 19 ++ .../array_zeroed_memory_index_access.sol | 22 +++ .../viaYul/function_pointers.sol | 25 +++ .../viaYul/return_storage_pointers.sol | 16 ++ 22 files changed, 475 insertions(+), 35 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/array_function_pointers.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_2d_zeroed_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_array_static.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_return_param_zeroed_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_zeroed_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_zeroed_memory_index_access.sol create mode 100644 test/libsolidity/semanticTests/viaYul/function_pointers.sol create mode 100644 test/libsolidity/semanticTests/viaYul/return_storage_pointers.sol diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 76eeb4fceec6..3fc649caf204 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2338,7 +2338,7 @@ TypePointers StructType::memoryMemberTypes() const TypePointers types; for (ASTPointer const& variable: m_struct.members()) if (variable->annotation().type->canLiveOutsideStorage()) - types.push_back(variable->annotation().type); + types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type)); return types; } diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index ba664dbb641f..28a4f69fbbf0 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -658,6 +658,8 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type) solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!"); solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented."); + solAssert(_type.baseType()->isValueType(), ""); + string functionName = "array_push_zero_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( @@ -794,6 +796,7 @@ string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) }); } + string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type) { solAssert(_type.dataStoredIn(DataLocation::Memory), ""); @@ -1178,7 +1181,7 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type) return Whiskers(R"( function (memPtr, value) { mstore(memPtr, value) - } + } )") ("functionName", functionName) .render(); @@ -1202,7 +1205,7 @@ string YulUtilFunctions::writeToMemoryFunction(Type const& _type) return Whiskers(R"( function (memPtr, value) { mstore(memPtr, (value)) - } + } )") ("functionName", functionName) ("cleanup", cleanupFunction(_type)) @@ -1334,28 +1337,112 @@ string YulUtilFunctions::allocationFunction() }); } -string YulUtilFunctions::allocateMemoryArrayFunction(ArrayType const& _type) +string YulUtilFunctions::zeroMemoryArrayFunction(ArrayType const& _type) { - solUnimplementedAssert(!_type.isByteArray(), ""); + if (_type.baseType()->hasSimpleZeroValueInMemory()) + return zeroMemoryFunction(*_type.baseType()); + return zeroComplexMemoryArrayFunction(_type); +} - string functionName = "allocate_memory_array_" + _type.identifier(); +string YulUtilFunctions::zeroMemoryFunction(Type const& _type) +{ + solAssert(_type.hasSimpleZeroValueInMemory(), ""); + + string functionName = "zero_memory_chunk_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( - function (length) -> memPtr { - memPtr := ((length)) - - mstore(memPtr, length) - + function (dataStart, dataSizeInBytes) { + calldatacopy(dataStart, calldatasize(), dataSizeInBytes) } )") ("functionName", functionName) - ("alloc", allocationFunction()) - ("allocSize", arrayAllocationSizeFunction(_type)) - ("dynamic", _type.isDynamicallySized()) .render(); }); } +string YulUtilFunctions::zeroComplexMemoryArrayFunction(ArrayType const& _type) +{ + solAssert(!_type.baseType()->hasSimpleZeroValueInMemory(), ""); + + string functionName = "zero_complex_memory_array_" + _type.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + solAssert(_type.memoryStride() == 32, ""); + return Whiskers(R"( + function (dataStart, dataSizeInBytes) { + for {let i := 0} lt(i, dataSizeInBytes) { i := add(i, ) } { + mstore(add(dataStart, i), ()) + } + } + )") + ("functionName", functionName) + ("stride", to_string(_type.memoryStride())) + ("zeroValue", zeroValueFunction(*_type.baseType(), false)) + .render(); + }); +} + +string YulUtilFunctions::allocateAndInitializeMemoryArrayFunction(ArrayType const& _type) +{ + solUnimplementedAssert(!_type.isByteArray(), ""); + + string functionName = "allocate_and_zero_memory_array_" + _type.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + return Whiskers(R"( + function (length) -> memPtr { + let allocSize := (length) + memPtr := (allocSize) + let dataStart := memPtr + let dataSize := allocSize + + dataStart := add(dataStart, 32) + dataSize := sub(dataSize, 32) + mstore(memPtr, length) + + (dataStart, dataSize) + } + )") + ("functionName", functionName) + ("alloc", allocationFunction()) + ("allocSize", arrayAllocationSizeFunction(_type)) + ("zeroArrayFunction", zeroMemoryArrayFunction(_type)) + ("dynamic", _type.isDynamicallySized()) + .render(); + }); +} + +string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType const& _type) +{ + string functionName = "allocate_and_initialize_memory_struct_" + _type.identifier(); + return m_functionCollector.createFunction(functionName, [&]() { + Whiskers templ(R"( + function () -> memPtr { + let allocSize := () + memPtr := (allocSize) + let offset := memPtr + <#member> + mstore(offset, ()) + offset := add(offset, 32) + + } + )"); + templ("functionName", functionName); + templ("alloc", allocationFunction()); + + TypePointers const& members = _type.memoryMemberTypes(); + templ("allocSize", _type.memoryDataSize().str()); + + vector> memberParams(members.size()); + for (size_t i = 0; i < members.size(); ++i) + { + solAssert(members[i]->memoryHeadSize() == 32, ""); + solAssert(members[i]->dataStoredIn(DataLocation::Memory), ""); + memberParams[i]["zeroValue"] = zeroValueFunction(*members[i], false); + } + templ("member", memberParams); + return templ.render(); + }); +} + string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) { if (_from.category() == Type::Category::Function) @@ -1884,23 +1971,58 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type) }); } -string YulUtilFunctions::zeroValueFunction(Type const& _type) +string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctionTypes) { - solUnimplementedAssert(_type.sizeOnStack() == 1, "Stacksize not yet implemented!"); - solUnimplementedAssert(_type.isValueType(), "Zero value for non-value types not yet implemented"); + solAssert(_type.category() != Type::Category::Mapping, ""); - string const functionName = "zero_value_for_" + _type.identifier(); + string const functionName = "zero_value_for_" + string(_splitFunctionTypes ? "split_" : "") + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { - return Whiskers(R"( - function () -> ret { - - } - )") + FunctionType const* fType = dynamic_cast(&_type); + if (fType && fType->kind() == FunctionType::Kind::External && _splitFunctionTypes) + return Whiskers(R"( + function () -> retAddress, retFunction { + retAddress := 0 + retFunction := 0 + } + )") ("functionName", functionName) - ("body", "ret := 0x0") .render(); - }); + + Whiskers templ(R"( + function () -> ret { + ret := + } + )"); + templ("functionName", functionName); + + if (_type.isValueType()) + { + solAssert(( + _type.hasSimpleZeroValueInMemory() || + (fType && (fType->kind() == FunctionType::Kind::Internal || fType->kind() == FunctionType::Kind::External)) + ), ""); + templ("zeroValue", "0"); + } + else + { + solAssert(_type.dataStoredIn(DataLocation::Memory), ""); + if (auto const* arrayType = dynamic_cast(&_type)) + { + if (_type.isDynamicallySized()) + templ("zeroValue", to_string(CompilerUtils::zeroPointer)); + else + templ("zeroValue", allocateAndInitializeMemoryArrayFunction(*arrayType) + "(" + to_string(unsigned(arrayType->length())) + ")"); + + } + else if (auto const* structType = dynamic_cast(&_type)) + templ("zeroValue", allocateAndInitializeMemoryStructFunction(*structType) + "()"); + else + solUnimplementedAssert(false, ""); + } + + return templ.render(); + }); } string YulUtilFunctions::storageSetToZeroFunction(Type const& _type) diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 8841e98adf92..b902f9f645fc 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -37,6 +37,7 @@ class Type; class ArrayType; class MappingType; class IntegerType; +class StructType; /** * Component that can generate various useful Yul functions. @@ -154,6 +155,7 @@ class YulUtilFunctions /// to store an array in memory given its length (internally encoded, not ABI encoded). /// The function reverts for too large lengths. std::string arrayAllocationSizeFunction(ArrayType const& _type); + /// @returns the name of a function that converts a storage slot number /// a memory pointer or a calldata pointer to the slot number / memory pointer / calldata pointer /// for the data position of an array which is stored in that slot / memory area / calldata area. @@ -250,10 +252,27 @@ class YulUtilFunctions /// Return value: pointer std::string allocationFunction(); - /// @returns the name of a function that allocates a memory array. + /// @returns the name of a function that zeroes an array. + /// signature: (dataStart, dataSizeInBytes) -> + std::string zeroMemoryArrayFunction(ArrayType const& _type); + + /// @returns the name of a function that zeroes a chunk of memory. + /// signature: (dataStart, dataSizeInBytes) -> + std::string zeroMemoryFunction(Type const& _type); + + /// @returns the name of a function that zeroes an array + /// where the base does not have simple zero value in memory. + /// signature: (dataStart, dataSizeInBytes) -> + std::string zeroComplexMemoryArrayFunction(ArrayType const& _type); + + /// @returns the name of a function that allocates and zeroes a memory array. /// For dynamic arrays it adds space for length and stores it. /// signature: (length) -> memPtr - std::string allocateMemoryArrayFunction(ArrayType const& _type); + std::string allocateAndInitializeMemoryArrayFunction(ArrayType const& _type); + + /// @returns the name of a function that allocates and zeroes a memory struct. + /// signature: (members) -> memPtr + std::string allocateAndInitializeMemoryStructFunction(StructType const& _type); /// @returns the name of the function that converts a value of type @a _from /// to a value of type @a _to. The resulting vale is guaranteed to be in range @@ -288,8 +307,9 @@ class YulUtilFunctions std::string negateNumberCheckedFunction(Type const& _type); /// @returns the name of a function that returns the zero value for the - /// provided type - std::string zeroValueFunction(Type const& _type); + /// provided type. + /// @param _splitFunctionTypes if false, returns two zeroes + std::string zeroValueFunction(Type const& _type, bool _splitFunctionTypes = true); /// @returns the name of a function that will set the given storage item to /// zero diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index 288da5937992..26f6f030961a 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -112,9 +113,10 @@ string IRGenerationContext::internalDispatch(size_t _in, size_t _out) for (auto const& contract: mostDerivedContract().annotation().linearizedBaseContracts) for (FunctionDefinition const* function: contract->definedFunctions()) if ( + FunctionType const* functionType = TypeProvider::function(*function)->asCallableFunction(false); !function->isConstructor() && - function->parameters().size() == _in && - function->returnParameters().size() == _out + TupleType(functionType->parameterTypes()).sizeOnStack() == _in && + TupleType(functionType->returnParameterTypes()).sizeOnStack() == _out ) { // 0 is reserved for uninitialized function pointers diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 2aff9c3f865a..5ae4b71d7408 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -133,6 +133,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) return m_context.functionCollector().createFunction(functionName, [&]() { Whiskers t(R"( function () { + } )"); @@ -142,9 +143,14 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) params += (params.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); t("params", params); string retParams; + string retInit; for (auto const& varDecl: _function.returnParameters()) + { retParams += (retParams.empty() ? "" : ", ") + m_context.addLocalVariable(*varDecl).commaSeparatedList(); + retInit += generateInitialAssignment(*varDecl); + } t("returns", retParams.empty() ? "" : " -> " + retParams); + t("initReturnVariables", retInit); t("body", generate(_function.body())); return t.render(); }); @@ -226,6 +232,13 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } } +string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl) +{ + IRGeneratorForStatements generator(m_context, m_utils); + generator.initializeLocalVar(_varDecl); + return generator.code(); +} + string IRGenerator::constructorCode(ContractDefinition const& _contract) { // Initialization of state variables in base-to-derived order. diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index d1ec580f61d4..e0c1dcd4f9e2 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -61,6 +61,9 @@ class IRGenerator /// Generates a getter for the given declaration and returns its name std::string generateGetter(VariableDeclaration const& _varDecl); + /// Generates code that assigns the initial value of the respective type. + std::string generateInitialAssignment(VariableDeclaration const& _varDecl); + std::string constructorCode(ContractDefinition const& _contract); std::string deployCode(ContractDefinition const& _contract); std::string callValueCheck(); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 8a98e8d3651e..57c8cb152903 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -154,6 +154,19 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va } } +void IRGeneratorForStatements::initializeLocalVar(VariableDeclaration const& _varDecl) +{ + solAssert(m_context.isLocalVariable(_varDecl), "Must be a local variable."); + + auto const* type = _varDecl.type(); + if (auto const* refType = dynamic_cast(type)) + if (refType->dataStoredIn(DataLocation::Storage) && refType->isPointer()) + return; + + IRVariable zero = zeroValue(*type); + assign(m_context.localVariable(_varDecl), zero); +} + void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _varDeclStatement) { if (Expression const* expression = _varDeclStatement.initialValue()) @@ -179,7 +192,10 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var else for (auto const& decl: _varDeclStatement.declarations()) if (decl) + { declare(m_context.addLocalVariable(*decl)); + initializeLocalVar(*decl); + } } bool IRGeneratorForStatements::visit(Conditional const& _conditional) @@ -670,7 +686,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) IRVariable value = convert(*arguments[0], *TypeProvider::uint256()); define(_functionCall) << - m_utils.allocateMemoryArrayFunction(arrayType) << + m_utils.allocateAndInitializeMemoryArrayFunction(arrayType) << "(" << value.commaSeparatedList() << ")\n"; @@ -1439,6 +1455,12 @@ std::ostream& IRGeneratorForStatements::define(IRVariable const& _var) return m_code; } +void IRGeneratorForStatements::declare(IRVariable const& _var) +{ + if (_var.type().sizeOnStack() > 0) + m_code << "let " << _var.commaSeparatedList() << "\n"; +} + void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare) { string output; @@ -1458,10 +1480,15 @@ void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable _rhs.commaSeparatedList() << ")\n"; } -void IRGeneratorForStatements::declare(IRVariable const& _var) + +IRVariable IRGeneratorForStatements::zeroValue(Type const& _type, bool _splitFunctionTypes) { - if (_var.type().sizeOnStack() > 0) - m_code << "let " << _var.commaSeparatedList() << "\n"; + IRVariable irVar{ + "zero_value_for_type_" + _type.identifier() + m_context.newYulVariable(), + _type + }; + define(irVar) << m_utils.zeroValueFunction(_type, _splitFunctionTypes) << "()\n"; + return irVar; } void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 39dbb67d77b9..710961cd768b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -46,6 +46,8 @@ class IRGeneratorForStatements: public ASTConstVisitor /// Generates code to initialize the given state variable. void initializeStateVar(VariableDeclaration const& _varDecl); + /// Generates code to initialize the given local variable. + void initializeLocalVar(VariableDeclaration const& _varDecl); void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Conditional const& _conditional) override; @@ -100,6 +102,11 @@ class IRGeneratorForStatements: public ASTConstVisitor void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define); + /// @returns an IRVariable with the zero + /// value of @a _type. + /// @param _splitFunctionTypes if false, returns two zeroes + IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true); + void appendAndOrOperatorCode(BinaryOperation const& _binOp); void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr); diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 82e974025a54..cb89a6911d0b 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -20,6 +20,7 @@ object \"C_6\" { function fun_f_5() { + } } @@ -69,6 +70,7 @@ object \"C_6\" { function fun_f_5() { + } function shift_right_224_unsigned(value) -> newValue { diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index fc88acf50039..24a2a10aa056 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -35,11 +35,18 @@ object \"C_10\" { } function fun_f_9() -> vloc__4_mpos { + let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() + vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos + vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr() leave } + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + } object \"C_10_deployed\" { code { @@ -131,6 +138,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4_mpos { + let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() + vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos + vloc__4_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr() leave @@ -147,6 +157,10 @@ object \"C_10\" { } + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + } } } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 428c7911eff9..8028e5dd6e08 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -23,11 +23,18 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32() + vloc__4 := zero_value_for_type_t_bytes32_1 + vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32() leave } + function zero_value_for_split_t_bytes32() -> ret { + ret := 0 + } + } object \"C_10_deployed\" { code { @@ -88,6 +95,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes32_1 := zero_value_for_split_t_bytes32() + vloc__4 := zero_value_for_type_t_bytes32_1 + vloc__4 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32() leave @@ -100,6 +110,10 @@ object \"C_10\" { } + function zero_value_for_split_t_bytes32() -> ret { + ret := 0 + } + } } } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index 4a348343b510..a9588d145575 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -27,6 +27,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() + vloc__4 := zero_value_for_type_t_bytes4_1 + let expr_6 := 0x61626364 vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6) leave @@ -40,6 +43,10 @@ object \"C_10\" { } + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 + } + } object \"C_10_deployed\" { code { @@ -104,6 +111,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() + vloc__4 := zero_value_for_type_t_bytes4_1 + let expr_6 := 0x61626364 vloc__4 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_6) leave @@ -124,6 +134,10 @@ object \"C_10\" { } + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 + } + } } } diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 4302701bdcd3..552712154dcc 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -39,11 +39,18 @@ object \"C_10\" { } function fun_f_9() -> vloc__4_mpos { + let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() + vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos + vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr() leave } + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + } object \"C_10_deployed\" { code { @@ -139,6 +146,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4_mpos { + let zero_value_for_type_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() + vloc__4_mpos := zero_value_for_type_t_string_memory_ptr_1_mpos + vloc__4_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr() leave @@ -155,6 +165,10 @@ object \"C_10\" { } + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + } } } diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 0b92fceea4ea..48c1146faeac 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -27,6 +27,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() + vloc__4 := zero_value_for_type_t_bytes4_1 + let expr_6 := 0xaabbccdd vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6) leave @@ -40,6 +43,10 @@ object \"C_10\" { } + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 + } + } object \"C_10_deployed\" { code { @@ -104,6 +111,9 @@ object \"C_10\" { } function fun_f_9() -> vloc__4 { + let zero_value_for_type_t_bytes4_1 := zero_value_for_split_t_bytes4() + vloc__4 := zero_value_for_type_t_bytes4_1 + let expr_6 := 0xaabbccdd vloc__4 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_6) leave @@ -124,6 +134,10 @@ object \"C_10\" { } + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 + } + } } } diff --git a/test/libsolidity/semanticTests/viaYul/array_function_pointers.sol b/test/libsolidity/semanticTests/viaYul/array_function_pointers.sol new file mode 100644 index 000000000000..5344ae67fe47 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_function_pointers.sol @@ -0,0 +1,29 @@ +contract C { + function f(uint n, uint m) public { + function() internal returns (uint)[] memory arr = new function() internal returns (uint)[](n); + arr[m](); + } + function f2(uint n, uint m, uint a, uint b) public { + function() internal returns (uint)[][] memory arr = new function() internal returns (uint)[][](n); + for (uint i = 0; i < n; ++i) + arr[i] = new function() internal returns (uint)[](m); + arr[a][b](); + } + function g(uint n, uint m) public { + function() external returns (uint)[] memory arr = new function() external returns (uint)[](n); + arr[m](); + } + function g2(uint n, uint m, uint a, uint b) public { + function() external returns (uint)[][] memory arr = new function() external returns (uint)[][](n); + for (uint i = 0; i < n; ++i) + arr[i] = new function() external returns (uint)[](m); + arr[a][b](); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256,uint256): 1823621, 12323 -> FAILURE +// f2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE +// g(uint256,uint256): 1823621, 12323 -> FAILURE +// g2(uint256,uint256,uint256,uint256): 18723921, 1823621, 123, 12323 -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_2d_zeroed_memory_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_2d_zeroed_memory_index_access.sol new file mode 100644 index 000000000000..aa1349cb82a0 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_2d_zeroed_memory_index_access.sol @@ -0,0 +1,24 @@ +contract C { + uint test1; + uint test2; + uint test3; + uint test4; + uint test5; + uint test6; + uint test7; + mapping (string => uint) map; + function set(string memory s, uint n, uint m, uint a, uint b) public returns (uint) { + map[s] = 0; + uint[][] memory x = new uint[][](n); + for (uint i = 0; i < n; ++i) + x[i] = new uint[](m); + return x[a][b]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 0, 0, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 3, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 3, 3, 32, "01234567890123456789012345678901" -> FAILURE +// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 5, 32, "01234567890123456789012345678901" -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_array_static.sol b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_array_static.sol new file mode 100644 index 000000000000..1f490ba59aa1 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_array_static.sol @@ -0,0 +1,22 @@ +contract C { + uint test1; + uint test2; + uint test3; + uint test4; + uint test5; + uint test6; + uint test7; + mapping (string => uint) map; + function set(string memory s, uint n, uint m) public returns (uint) { + map[s] = 0; + uint[4][] memory x = new uint[4][](n); + return x[m][0]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(string,uint256,uint256): 0x60, 2, 0, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256): 0x60, 2, 1, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256): 0x60, 2, 2, 32, "01234567890123456789012345678901" -> FAILURE +// set(string,uint256,uint256): 0x60, 200, 199, 32, "01234567890123456789012345678901" -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_return_param_zeroed_memory_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_return_param_zeroed_memory_index_access.sol new file mode 100644 index 000000000000..31dd0a66a60c --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_return_param_zeroed_memory_index_access.sol @@ -0,0 +1,17 @@ +contract C { + uint test1; + uint test2; + uint test3; + uint test4; + uint test5; + uint test6; + uint test7; + mapping (string => uint) map; + function set(string memory s) public returns (uint[3] memory x, uint[2] memory y, uint[] memory z, uint t) { + map[s] = 0; + } +} +// ==== +// compileViaYul: also +// ---- +// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0, 0, 0, 0, 0, 0xe0, 0, 0 diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_zeroed_memory_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_zeroed_memory_index_access.sol new file mode 100644 index 000000000000..6cf73bd8e870 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_static_zeroed_memory_index_access.sol @@ -0,0 +1,19 @@ +contract C { + uint test1; + uint test2; + uint test3; + uint test4; + uint test5; + uint test6; + uint test7; + mapping (string => uint) map; + function set(string memory s) public returns (uint) { + map[s] = 0; + uint[3] memory x; + return x[2]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(string): 0x20, 32, "01234567890123456789012345678901" -> 0 diff --git a/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_zeroed_memory_index_access.sol b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_zeroed_memory_index_access.sol new file mode 100644 index 000000000000..1f9e70db7bd4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/array_memory_allocation/array_zeroed_memory_index_access.sol @@ -0,0 +1,22 @@ +contract C { + uint test1; + uint test2; + uint test3; + uint test4; + uint test5; + uint test6; + uint test7; + mapping (string => uint) map; + function set(string memory s, uint n, uint a) public returns (uint) { + map[s] = 0; + uint[] memory x = new uint[](n); + return x[a]; + } +} +// ==== +// compileViaYul: also +// ---- +// set(string,uint256,uint256): 0x60, 5, 0, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256): 0x60, 5, 1, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256): 0x60, 5, 4, 32, "01234567890123456789012345678901" -> 0 +// set(string,uint256,uint256): 0x60, 5, 5, 32, "01234567890123456789012345678901" -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/function_pointers.sol b/test/libsolidity/semanticTests/viaYul/function_pointers.sol new file mode 100644 index 000000000000..5bd433a3d2a4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/function_pointers.sol @@ -0,0 +1,25 @@ +contract C { + function f() public { + function() internal returns (uint) _f; + _f(); + } + function g() public { + function() external returns (uint) _g; + _g(); + } + function h1() internal returns (function() internal returns (uint) _h) {} + function h2() public { + h1()(); + } + function k1() internal returns (function() external returns (uint) _k) {} + function k2() public { + k1()(); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> FAILURE +// g() -> FAILURE +// h2() -> FAILURE +// k2() -> FAILURE diff --git a/test/libsolidity/semanticTests/viaYul/return_storage_pointers.sol b/test/libsolidity/semanticTests/viaYul/return_storage_pointers.sol new file mode 100644 index 000000000000..d0085dec19f6 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/return_storage_pointers.sol @@ -0,0 +1,16 @@ +contract C { + uint[] arr1; + uint[][] arr2; + function f() internal returns (uint[] storage ptr1, uint[][] storage ptr2) { + ptr1 = arr1; + ptr2 = arr2; + } + function g() public returns (uint, uint) { + return (arr1.length, arr2.length); + } + +} +// ==== +// compileViaYul: also +// ---- +// g() -> 0, 0 From ef2bef9ddc2562864285f8f386f005fa36e58a2f Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 2 Apr 2020 20:30:43 +0530 Subject: [PATCH 151/165] Added error for interface function with modifiers; test case --- libsolidity/analysis/SyntaxChecker.cpp | 4 +++- .../588_interface_function_modifier.sol | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 74fa8d458cfb..ba973bffa110 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -303,7 +303,9 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function) ); } - if (!_function.isImplemented() && !_function.modifiers().empty()) + if (m_isInterface && !_function.modifiers().empty()) + m_errorReporter.syntaxError(_function.location(), "Functions in interfaces cannot have modifiers."); + else if (!_function.isImplemented() && !_function.modifiers().empty()) m_errorReporter.syntaxError(_function.location(), "Functions without implementation cannot have modifiers."); return true; diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol new file mode 100644 index 000000000000..b94334d38770 --- /dev/null +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol @@ -0,0 +1,6 @@ +interface I { + function f() external m pure returns (uint); + modifier m() { _; } +} +// ---- +// SyntaxError: (16-60): Functions in interfaces cannot have modifiers. From 0d3303e4af0878a082043c66f36e681f131fc6b2 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 2 Apr 2020 17:46:29 +0200 Subject: [PATCH 152/165] Changelog entry for immutable variables. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 82a40eceddf7..2c757e402d35 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Important Bugfixes: Language Features: * Allow local storage variables to be declared without initialization, as long as they are assigned before they are accessed. + * State variables can be marked ``immutable`` which causes them to be read-only, but assignable in the constructor. The value will be stored directly in the code. Compiler Features: From bdcfd71f343f701d3fccf12ca99c2cbae2705dcc Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 2 Apr 2020 18:26:33 +0200 Subject: [PATCH 153/165] Skip verification for external access. --- libsolidity/analysis/ImmutableValidator.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index e80902009c63..6e0d0f6c796b 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -74,6 +74,11 @@ bool ImmutableValidator::visit(MemberAccess const& _memberAccess) { _memberAccess.expression().accept(*this); + if (auto contractType = dynamic_cast(_memberAccess.expression().annotation().type)) + if (!contractType->isSuper()) + // external access, no analysis needed. + return false; + if (auto varDecl = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) analyseVariableReference(*varDecl, _memberAccess); else if (auto funcType = dynamic_cast(_memberAccess.annotation().type)) @@ -187,7 +192,8 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va else if (m_inConstructionContext) m_errorReporter.typeError( _expression.location(), - "Immutable variables cannot be read during contract creation time, which means they cannot be read in the constructor or any function or modifier called from it." + "Immutable variables cannot be read during contract creation time, which means " + "they cannot be read in the constructor or any function or modifier called from it." ); } From d7a39c86ce135b6c6f5435f3099fc0dafe589755 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 2 Apr 2020 17:13:31 +0200 Subject: [PATCH 154/165] Accessors for immutable variables. --- libsolidity/codegen/ContractCompiler.cpp | 2 -- libsolidity/codegen/ExpressionCompiler.cpp | 20 ++++++++++++++----- .../semanticTests/immutable/complexGetter.sol | 12 +++++++++++ .../semanticTests/immutable/getter.sol | 5 +++++ .../immutable/getter_call_in_constructor.sol | 17 ++++++++++++++++ 5 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 test/libsolidity/semanticTests/immutable/complexGetter.sol create mode 100644 test/libsolidity/semanticTests/immutable/getter.sol create mode 100644 test/libsolidity/semanticTests/immutable/getter_call_in_constructor.sol diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 49b08b6dae7d..822ce3b667ae 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -566,8 +566,6 @@ bool ContractCompiler::visit(VariableDeclaration const& _variableDeclaration) if (_variableDeclaration.isConstant()) ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendConstStateVariableAccessor(_variableDeclaration); - else if (_variableDeclaration.immutable()) - solUnimplementedAssert(false, ""); else ExpressionCompiler(m_context, m_optimiserSettings.runOrderLiterals) .appendStateVariableAccessor(_variableDeclaration); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index a406cdeb843f..a02497561279 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -91,16 +91,22 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { - solAssert(!_varDecl.isConstant() && !_varDecl.immutable(), ""); + solAssert(!_varDecl.isConstant(), ""); CompilerContext::LocationSetter locationSetter(m_context, _varDecl); FunctionType accessorType(_varDecl); TypePointers paramTypes = accessorType.parameterTypes(); + if (_varDecl.immutable()) + solAssert(paramTypes.empty(), ""); + m_context.adjustStackOffset(1 + CompilerUtils::sizeOnStack(paramTypes)); - // retrieve the position of the variable - auto const& location = m_context.storageLocationOfVariable(_varDecl); - m_context << location.first << u256(location.second); + if (!_varDecl.immutable()) + { + // retrieve the position of the variable + auto const& location = m_context.storageLocationOfVariable(_varDecl); + m_context << location.first << u256(location.second); + } TypePointer returnType = _varDecl.annotation().type; @@ -182,6 +188,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& solAssert(returnTypes.size() >= 1, ""); if (StructType const* structType = dynamic_cast(returnType)) { + solAssert(!_varDecl.immutable(), ""); // remove offset m_context << Instruction::POP; auto const& names = accessorType.returnParameterNames(); @@ -208,7 +215,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& { // simple value or array solAssert(returnTypes.size() == 1, ""); - StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true); + if (_varDecl.immutable()) + ImmutableItem(m_context, _varDecl).retrieveValue(SourceLocation()); + else + StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true); utils().convertType(*returnType, *returnTypes.front()); retSizeOnStack = returnTypes.front()->sizeOnStack(); } diff --git a/test/libsolidity/semanticTests/immutable/complexGetter.sol b/test/libsolidity/semanticTests/immutable/complexGetter.sol new file mode 100644 index 000000000000..8511208475ef --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/complexGetter.sol @@ -0,0 +1,12 @@ +contract C { + function() external returns (uint, uint) immutable public x = this.f; + function f() external pure returns (uint, uint) { + return (1, 2); + } + + function test() external returns (uint, uint) { + return this.x()(); + } +} +// ---- +// test() -> 1, 2 diff --git a/test/libsolidity/semanticTests/immutable/getter.sol b/test/libsolidity/semanticTests/immutable/getter.sol new file mode 100644 index 000000000000..bb4b191cf9f6 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/getter.sol @@ -0,0 +1,5 @@ +contract C { + uint immutable public x = 1; +} +// ---- +// x() -> 1 diff --git a/test/libsolidity/semanticTests/immutable/getter_call_in_constructor.sol b/test/libsolidity/semanticTests/immutable/getter_call_in_constructor.sol new file mode 100644 index 000000000000..e4aa474f2b05 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/getter_call_in_constructor.sol @@ -0,0 +1,17 @@ +contract A { + uint immutable public x = 1; + uint public y; + constructor() public { + y = this.x(); + } +} +contract C { + function f() public returns (bool) { + try new A() { return false; } + catch { return true; } + } +} +// ==== +// EVMVersion: >=tangerineWhistle +// ---- +// f() -> true From 7f5857a14620326b4113cc9e48611f832d021db2 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Thu, 26 Mar 2020 15:11:00 -0400 Subject: [PATCH 155/165] Delete copy/move on annotation polymorphic bases --- libsolidity/ast/ASTAnnotations.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index a724472d0224..021a742f5417 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -47,6 +47,14 @@ using TypePointer = Type const*; struct ASTAnnotation { + ASTAnnotation() = default; + + ASTAnnotation(ASTAnnotation const&) = delete; + ASTAnnotation(ASTAnnotation&&) = delete; + + ASTAnnotation& operator=(ASTAnnotation const&) = delete; + ASTAnnotation& operator=(ASTAnnotation&&) = delete; + virtual ~ASTAnnotation() = default; }; @@ -58,7 +66,16 @@ struct DocTag struct StructurallyDocumentedAnnotation { + StructurallyDocumentedAnnotation() = default; + + StructurallyDocumentedAnnotation(StructurallyDocumentedAnnotation const&) = delete; + StructurallyDocumentedAnnotation(StructurallyDocumentedAnnotation&&) = delete; + + StructurallyDocumentedAnnotation& operator=(StructurallyDocumentedAnnotation const&) = delete; + StructurallyDocumentedAnnotation& operator=(StructurallyDocumentedAnnotation&&) = delete; + virtual ~StructurallyDocumentedAnnotation() = default; + /// Mapping docstring tag name -> content. std::multimap docTags; }; @@ -75,6 +92,16 @@ struct SourceUnitAnnotation: ASTAnnotation struct ScopableAnnotation { + ScopableAnnotation() = default; + + ScopableAnnotation(ScopableAnnotation const&) = delete; + ScopableAnnotation(ScopableAnnotation&&) = delete; + + ScopableAnnotation& operator=(ScopableAnnotation const&) = delete; + ScopableAnnotation& operator=(ScopableAnnotation&&) = delete; + + virtual ~ScopableAnnotation() = default; + /// The scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. ASTNode const* scope = nullptr; From d68c526eaacc1072e8c0ddb4b3513897cce352b7 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Apr 2020 11:56:51 +0200 Subject: [PATCH 156/165] Disallow external function pointers as immutables. --- libsolidity/analysis/TypeChecker.cpp | 8 ++++++++ .../semanticTests/immutable/complexGetter.sol | 12 ----------- .../immutable/external_function_pointer.sol | 20 ------------------- .../immutable/external_function_pointer.sol | 5 +++++ 4 files changed, 13 insertions(+), 32 deletions(-) delete mode 100644 test/libsolidity/semanticTests/immutable/complexGetter.sol delete mode 100644 test/libsolidity/semanticTests/immutable/external_function_pointer.sol create mode 100644 test/libsolidity/syntaxTests/immutable/external_function_pointer.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8e7bef338d6e..2bdc706a2539 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -481,8 +481,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) ); } else if (_variable.immutable()) + { if (!_variable.type()->isValueType()) m_errorReporter.typeError(_variable.location(), "Immutable variables cannot have a non-value type."); + if ( + auto const* functionType = dynamic_cast(_variable.type()); + functionType && functionType->kind() == FunctionType::Kind::External + ) + m_errorReporter.typeError(_variable.location(), "Immutable variables of external function type are not yet supported."); + solAssert(_variable.type()->sizeOnStack() == 1 || m_errorReporter.hasErrors(), ""); + } if (!_variable.isStateVariable()) { diff --git a/test/libsolidity/semanticTests/immutable/complexGetter.sol b/test/libsolidity/semanticTests/immutable/complexGetter.sol deleted file mode 100644 index 8511208475ef..000000000000 --- a/test/libsolidity/semanticTests/immutable/complexGetter.sol +++ /dev/null @@ -1,12 +0,0 @@ -contract C { - function() external returns (uint, uint) immutable public x = this.f; - function f() external pure returns (uint, uint) { - return (1, 2); - } - - function test() external returns (uint, uint) { - return this.x()(); - } -} -// ---- -// test() -> 1, 2 diff --git a/test/libsolidity/semanticTests/immutable/external_function_pointer.sol b/test/libsolidity/semanticTests/immutable/external_function_pointer.sol deleted file mode 100644 index c815a18c3d20..000000000000 --- a/test/libsolidity/semanticTests/immutable/external_function_pointer.sol +++ /dev/null @@ -1,20 +0,0 @@ -contract D { - function f() external view returns (uint256) { - return 42; - } -} -contract C { - D d; - function() external view returns(uint256) immutable z; - constructor() public { - d = new D(); - z = d.f; - } - function f() public view returns (uint256) { - assert(z.address == address(d)); - assert(z.selector == D.f.selector); - return z(); - } -} -// ---- -// f() -> 42 diff --git a/test/libsolidity/syntaxTests/immutable/external_function_pointer.sol b/test/libsolidity/syntaxTests/immutable/external_function_pointer.sol new file mode 100644 index 000000000000..7ab8393cf42f --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/external_function_pointer.sol @@ -0,0 +1,5 @@ +contract C { + function() external immutable f; +} +// ---- +// TypeError: (17-48): Immutable variables of external function type are not yet supported. From 205063f86b89050515c1f34fac0d442a9599b231 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Fri, 3 Apr 2020 23:47:10 -0400 Subject: [PATCH 157/165] Delete copy and move operations for ASTVisitor and ASTConstVisitor --- libsolidity/ast/ASTVisitor.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 90dad003a18b..db67dc392137 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -41,7 +41,16 @@ namespace solidity::frontend class ASTVisitor { public: + ASTVisitor() = default; + + ASTVisitor(ASTVisitor const&) = delete; + ASTVisitor(ASTVisitor&&) = delete; + + ASTVisitor& operator=(ASTVisitor const&) = delete; + ASTVisitor& operator=(ASTVisitor&&) = delete; + virtual ~ASTVisitor() = default; + virtual bool visit(SourceUnit& _node) { return visitNode(_node); } virtual bool visit(PragmaDirective& _node) { return visitNode(_node); } virtual bool visit(ImportDirective& _node) { return visitNode(_node); } @@ -158,7 +167,16 @@ class ASTVisitor class ASTConstVisitor { public: + ASTConstVisitor() = default; + + ASTConstVisitor(ASTConstVisitor const&) = delete; + ASTConstVisitor(ASTConstVisitor&&) = delete; + + ASTConstVisitor& operator=(ASTConstVisitor const&) = delete; + ASTConstVisitor& operator=(ASTConstVisitor&&) = delete; + virtual ~ASTConstVisitor() = default; + virtual bool visit(SourceUnit const& _node) { return visitNode(_node); } virtual bool visit(PragmaDirective const& _node) { return visitNode(_node); } virtual bool visit(ImportDirective const& _node) { return visitNode(_node); } From 1847536d6d88c53c9a0614259cc9d8fde196bb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 6 Apr 2020 10:15:13 +0200 Subject: [PATCH 158/165] reference-types.rst: Minor text correction, itself -> themselves --- docs/types/reference-types.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 1566a88591d8..09e8633946d8 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -500,7 +500,7 @@ shown in the following example: The contract does not provide the full functionality of a crowdfunding contract, but it contains the basic concepts necessary to understand structs. -Struct types can be used inside mappings and arrays and they can itself +Struct types can be used inside mappings and arrays and they can themselves contain mappings and arrays. It is not possible for a struct to contain a member of its own type, From 303345b12c7d969a241e8242831e2b14e3d488f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 6 Apr 2020 10:15:42 +0200 Subject: [PATCH 159/165] reference-types.rst: Fix incorrectly wrapped line in the array slice section --- docs/types/reference-types.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 09e8633946d8..f7aca719037c 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -387,7 +387,7 @@ If ``start`` is greater than ``end`` or if ``end`` is greater than the length of the array, an exception is thrown. Both ``start`` and ``end`` are optional: ``start`` defaults - to ``0`` and ``end`` defaults to the length of the array. +to ``0`` and ``end`` defaults to the length of the array. Array slices do not have any members. They are implicitly convertible to arrays of their underlying type From 2cfa44bba38fcc593c17a1975f4cedb3577cfd7b Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 6 Apr 2020 10:50:00 +0200 Subject: [PATCH 160/165] Allow constructing symbolic arrays from smt sort --- libsolidity/formal/SymbolicVariables.cpp | 13 +++++++++++++ libsolidity/formal/SymbolicVariables.h | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp index 8f285c883227..549fc05e9652 100644 --- a/libsolidity/formal/SymbolicVariables.cpp +++ b/libsolidity/formal/SymbolicVariables.cpp @@ -218,15 +218,28 @@ SymbolicArrayVariable::SymbolicArrayVariable( solAssert(isArray(m_type->category()), ""); } +SymbolicArrayVariable::SymbolicArrayVariable( + SortPointer _sort, + string _uniqueName, + EncodingContext& _context +): + SymbolicVariable(move(_sort), move(_uniqueName), _context) +{ + solAssert(m_sort->kind == Kind::Array, ""); +} + smt::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer const& _targetType) const { if (_targetType) + { + solAssert(m_originalType, ""); // StringLiterals are encoded as SMT arrays in the generic case, // but they can also be compared/assigned to fixed bytes, in which // case they'd need to be encoded as numbers. if (auto strType = dynamic_cast(m_originalType)) if (_targetType->category() == frontend::Type::Category::FixedBytes) return smt::Expression(u256(toHex(util::asBytes(strType->value()), util::HexPrefix::Add))); + } return SymbolicVariable::currentValue(_targetType); } diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h index be75931f29af..e1c28a8b5c73 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -47,6 +47,8 @@ class SymbolicVariable EncodingContext& _context ); + SymbolicVariable(SymbolicVariable&&) = default; + virtual ~SymbolicVariable() = default; virtual Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const; @@ -212,6 +214,13 @@ class SymbolicArrayVariable: public SymbolicVariable std::string _uniqueName, EncodingContext& _context ); + SymbolicArrayVariable( + SortPointer _sort, + std::string _uniqueName, + EncodingContext& _context + ); + + SymbolicArrayVariable(SymbolicArrayVariable&&) = default; Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const override; }; From 81652686bed7c3eed85ea63f012562da478101f8 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 2 Apr 2020 17:27:35 +0200 Subject: [PATCH 161/165] Debug information for immutable references. --- libevmasm/Assembly.cpp | 9 ++--- libevmasm/LinkerObject.h | 6 ++-- libsolidity/codegen/CompilerContext.cpp | 8 +---- libsolidity/interface/StandardCompiler.cpp | 36 ++++++++++++++++--- .../standard_immutable_references/input.json | 18 ++++++++++ .../standard_immutable_references/output.json | 2 ++ 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 test/cmdlineTests/standard_immutable_references/input.json create mode 100644 test/cmdlineTests/standard_immutable_references/output.json diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index e67ccb8f502e..fa6ea4f16ba3 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -530,7 +530,7 @@ LinkerObject const& Assembly::assemble() const LinkerObject& ret = m_assembledObject; size_t subTagSize = 1; - map> immutableReferencesBySub; + map>> immutableReferencesBySub; for (auto const& sub: m_subs) { auto const& linkerObject = sub->assemble(); @@ -554,7 +554,7 @@ LinkerObject const& Assembly::assemble() const for (auto const& i: m_items) if (i.type() == AssignImmutable) { - i.setImmutableOccurrences(immutableReferencesBySub[i.data()].size()); + i.setImmutableOccurrences(immutableReferencesBySub[i.data()].second.size()); setsImmutables = true; } else if (i.type() == PushImmutable) @@ -660,11 +660,12 @@ LinkerObject const& Assembly::assemble() const break; case PushImmutable: ret.bytecode.push_back(uint8_t(Instruction::PUSH32)); - ret.immutableReferences[i.data()].emplace_back(ret.bytecode.size()); + ret.immutableReferences[i.data()].first = m_immutables.at(i.data()); + ret.immutableReferences[i.data()].second.emplace_back(ret.bytecode.size()); ret.bytecode.resize(ret.bytecode.size() + 32); break; case AssignImmutable: - for (auto const& offset: immutableReferencesBySub[i.data()]) + for (auto const& offset: immutableReferencesBySub[i.data()].second) { ret.bytecode.push_back(uint8_t(Instruction::DUP1)); // TODO: should we make use of the constant optimizer methods for pushing the offsets? diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index ccf5588bb334..ab0e26507261 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -40,9 +40,9 @@ struct LinkerObject /// need to be replaced by the actual addresses by the linker. std::map linkReferences; - /// Map from hashes of the identifiers of immutable variables to a list of offsets into the bytecode - /// that refer to their values. - std::map> immutableReferences; + /// Map from hashes of the identifiers of immutable variables to the full identifier of the immutable and + /// to a list of offsets into the bytecode that refer to their values. + std::map>> immutableReferences; /// Appends the bytecode of @a _other and incorporates its link references. void append(LinkerObject const& _other); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 6984a030ba60..06080afbd4d5 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -90,13 +90,7 @@ size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variab vector CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable) { - string baseName = - _variable.annotation().contract->fullyQualifiedName() + - "." + - _variable.name() + - " (" + - to_string(_variable.id()) + - ")"; + string baseName = to_string(_variable.id()); solAssert(_variable.annotation().type->sizeOnStack() > 0, ""); if (_variable.annotation().type->sizeOnStack() == 1) return {baseName}; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 77e00df057a8..00662718ed90 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -234,6 +234,7 @@ bool isBinaryRequested(Json::Value const& _outputSelection) "wast", "wasm", "ewasm.wast", "ewasm.wasm", "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", + "evm.deployedBytecode.immutableReferences", "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences", "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" @@ -309,13 +310,36 @@ Json::Value formatLinkReferences(std::map const& linkRefere return ret; } -Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap) +Json::Value formatImmutableReferences(map>> const& _immutableReferences) +{ + Json::Value ret(Json::objectValue); + + for (auto const& immutableReference: _immutableReferences) + { + auto const& [identifier, byteOffsets] = immutableReference.second; + Json::Value array(Json::arrayValue); + for (size_t byteOffset: byteOffsets) + { + Json::Value byteRange(Json::arrayValue); + byteRange.append(Json::UInt(byteOffset)); + byteRange.append(Json::UInt(32)); // immutable references are currently always 32 bytes wide + array.append(byteRange); + } + ret[identifier] = array; + } + + return ret; +} + +Json::Value collectEVMObject(evmasm::LinkerObject const& _object, string const* _sourceMap, bool _runtimeObject) { Json::Value output = Json::objectValue; output["object"] = _object.toHex(); output["opcodes"] = evmasm::disassemble(_object.bytecode); output["sourceMap"] = _sourceMap ? *_sourceMap : ""; output["linkReferences"] = formatLinkReferences(_object.linkReferences); + if (_runtimeObject) + output["immutableReferences"] = formatImmutableReferences(_object.immutableReferences); return output; } @@ -982,19 +1006,21 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting )) evmData["bytecode"] = collectEVMObject( compilerStack.object(contractName), - compilerStack.sourceMapping(contractName) + compilerStack.sourceMapping(contractName), + false ); if (compilationSuccess && isArtifactRequested( _inputsAndSettings.outputSelection, file, name, - { "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences" }, + { "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", "evm.deployedBytecode.immutableReferences" }, wildcardMatchesExperimental )) evmData["deployedBytecode"] = collectEVMObject( compilerStack.runtimeObject(contractName), - compilerStack.runtimeSourceMapping(contractName) + compilerStack.runtimeSourceMapping(contractName), + true ); if (!evmData.empty()) @@ -1081,7 +1107,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) { "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" }, wildcardMatchesExperimental )) - output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, object.sourceMappings.get()); + output["contracts"][sourceName][contractName]["evm"]["bytecode"] = collectEVMObject(*object.bytecode, object.sourceMappings.get(), false); if (isArtifactRequested(_inputsAndSettings.outputSelection, sourceName, contractName, "irOptimized", wildcardMatchesExperimental)) output["contracts"][sourceName][contractName]["irOptimized"] = stack.print(); diff --git a/test/cmdlineTests/standard_immutable_references/input.json b/test/cmdlineTests/standard_immutable_references/input.json new file mode 100644 index 000000000000..15213be74eb1 --- /dev/null +++ b/test/cmdlineTests/standard_immutable_references/input.json @@ -0,0 +1,18 @@ +{ + "language": "Solidity", + "sources": { + "a.sol": { + "content": "contract A { uint256 immutable x = 1; function f() public view returns (uint256) { return x; } }" + } + }, + "settings": { + "evmVersion": "petersburg", + "outputSelection": { + "*": { + "A": [ + "evm.deployedBytecode.immutableReferences" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json new file mode 100644 index 000000000000..1ba91eff73ea --- /dev/null +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -0,0 +1,2 @@ +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[[77,32]]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} From 06562e3431e0b77800577755ed3998d55ad90528 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Apr 2020 11:11:20 +0200 Subject: [PATCH 162/165] Prepare changelog for 0.6.5. --- Changelog.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Changelog.md b/Changelog.md index 2c757e402d35..17d4fd0aec93 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,7 @@ -### 0.6.5 (unreleased) +### 0.6.5 (2020-04-06) Important Bugfixes: - * Code Generator: Restrict the size of dynamic memory arrays to 64 bits during creation at runtime fixing a possible overflow. + * Code Generator: Restrict the length of dynamic memory arrays to 64 bits during creation at runtime fixing a possible overflow. Language Features: @@ -10,17 +10,17 @@ Language Features: Compiler Features: - * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. * Commandline Interface: Enable output of storage layout with `--storage-layout`. + * Metadata: Added support for IPFS hashes of large files that need to be split in multiple chunks. Bugfixes: + * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. * Inline Assembly: Fix internal error when accessing invalid constant variables. * Inline Assembly: Fix internal error when accessing functions. + * JSON AST: Always add pointer suffix for memory reference types. * Reference Resolver: Fix internal error when accessing invalid struct members. * Type Checker: Fix internal errors when assigning nested tuples. - * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. - * JSON AST: Always add pointer suffix for memory reference types. ### 0.6.4 (2020-03-10) From 84d7bac4f6468b5aa354a6824d3f984288c7b8b5 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 6 Apr 2020 11:21:53 +0200 Subject: [PATCH 163/165] Format immutable references similarly to link references. --- libsolidity/interface/StandardCompiler.cpp | 6 +++--- test/cmdlineTests/standard_immutable_references/output.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 00662718ed90..a97114e832e3 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -320,9 +320,9 @@ Json::Value formatImmutableReferences(map>> co Json::Value array(Json::arrayValue); for (size_t byteOffset: byteOffsets) { - Json::Value byteRange(Json::arrayValue); - byteRange.append(Json::UInt(byteOffset)); - byteRange.append(Json::UInt(32)); // immutable references are currently always 32 bytes wide + Json::Value byteRange(Json::objectValue); + byteRange["start"] = Json::UInt(byteOffset); + byteRange["length"] = Json::UInt(32); // immutable references are currently always 32 bytes wide array.append(byteRange); } ret[identifier] = array; diff --git a/test/cmdlineTests/standard_immutable_references/output.json b/test/cmdlineTests/standard_immutable_references/output.json index 1ba91eff73ea..2788a8e732f8 100644 --- a/test/cmdlineTests/standard_immutable_references/output.json +++ b/test/cmdlineTests/standard_immutable_references/output.json @@ -1,2 +1,2 @@ -{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[[77,32]]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! +{"contracts":{"a.sol":{"A":{"evm":{"deployedBytecode":{"immutableReferences":{"3":[{"length":32,"start":77}]},"linkReferences":{},"object":"bytecode removed","opcodes":"opcodes removed","sourceMap":"0:96:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;0:96:0;;;;;;;;;;;;;;;;12:1:-1;9;2:12;38:56:0;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;72:7;90:1;83:8;;38:56;:::o"}}}}},"errors":[{"component":"general","formattedMessage":"a.sol: Warning: Source file does not specify required compiler version! ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":-1,"file":"a.sol","start":-1},"type":"Warning"}],"sources":{"a.sol":{"id":0}}} From 4a23ce087ca868a0fe74f80ba976f9e7c36ee107 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 6 Apr 2020 11:22:07 +0200 Subject: [PATCH 164/165] Document immutable references output. --- docs/using-the-compiler.rst | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 8d647a4a7c09..02218592e687 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -302,7 +302,8 @@ Input Description // evm.bytecode.opcodes - Opcodes list // evm.bytecode.sourceMap - Source mapping (useful for debugging) // evm.bytecode.linkReferences - Link references (if unlinked object) - // evm.deployedBytecode* - Deployed bytecode (has the same options as evm.bytecode) + // evm.deployedBytecode* - Deployed bytecode (has all the options that evm.bytecode has) + // evm.deployedBytecode.immutableReferences - Map from AST ids to bytecode ranges that reference immutables // evm.methodIdentifiers - The list of function hashes // evm.gasEstimates - Function gas estimates // ewasm.wast - eWASM S-expressions format (not supported at the moment) @@ -424,8 +425,14 @@ Output Description } } }, - // The same layout as above. - "deployedBytecode": { }, + "deployedBytecode": { + ..., // The same layout as above. + "immutableReferences": [ + // There are two references to the immutable with AST ID 3, both 32 bytes long. One is + // at bytecode offset 42, the other at bytecode offset 80. + "3": [{ "start": 42, "length": 32 }, { "start": 80, "length": 32 }] + ] + }, // The list of function hashes "methodIdentifiers": { "delegate(address)": "5c19a95c" From 30c9705c146432447cf14b98a4ca5aa41b57ac5d Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Apr 2020 13:17:01 +0200 Subject: [PATCH 165/165] Update buglist. --- docs/bugs_by_version.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0d0f30c48e71..b123930167b7 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1013,5 +1013,9 @@ "MemoryArrayCreationOverflow" ], "released": "2020-03-10" + }, + "0.6.5": { + "bugs": [], + "released": "2020-04-06" } } \ No newline at end of file