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 321ebe088..e3464029c 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 21c0b8c91..b26fd166f 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 000000000..6e63e4710 --- /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 000000000..c7e833932 --- /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 3ea080686..2fcbb2faf 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 000000000..af03cd2bc --- /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 6e63e4710..8f3fd0f7f 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 c7e833932..7778d6567 100644 --- a/tools/yulPhaser/PairSelections.h +++ b/tools/yulPhaser/PairSelections.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -50,4 +51,49 @@ public: 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 93aa432fa..52cde9590 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 e73260d7a..cbec90f78 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 @@ public: 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 9bcab9923..3456a6640 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 2fcbb2faf..eb4b8241c 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 000000000..29a516919 --- /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 b26fd166f..4791087b5 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 000000000..4010f89d3 --- /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 000000000..b18f195ef --- /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 29a516919..49f6e7f02 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 4010f89d3..f639d8f6a 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 b18f195ef..c934d71de 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 52cde9590..f9000921f 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 cbec90f78..a59c7eed1 100644 --- a/test/yulPhaser/Common.h +++ b/test/yulPhaser/Common.h @@ -59,6 +59,11 @@ public: /// 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 3456a6640..efc511a80 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 eb4b8241c..da6995e38 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 98532c9dc..3e228f627 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 b39f5dad5..61702634f 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 f4f42346d..29c82efed 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 @@ public: ); 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 aaa0a0b05..0d32e9c1d 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 756a410f7..ae32960b4 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 a7600d894..bab475c4e 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -112,4 +112,57 @@ private: 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 e3464029c..f1a0cd001 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 f1a0cd001..99402d56b 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 49f6e7f02..66852ed55 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") && result2 == Chromosome("aaa")) || - (result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("Taa")) || - (result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTa")) || - (result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") && result2 == Chromosome("TTT")) + result1 == Chromosome("TTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aTTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaTTTTTTTTTTTTTTTTTT") || + result1 == Chromosome("aaaTTTTTTTTTTTTTTTTT") + )); + BOOST_TEST(( + 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 3e228f627..2363256e4 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 ae32960b4..fa37ac5e3 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 f639d8f6a..86f815198 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 c934d71de..bff48c52b 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 61702634f..ec63eb3bb 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 99402d56b..4af735d0b 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 ebf54b3a4..829aab9e4 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 393f3da8b..ece4e581c 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 82c2b446b..fad5a127f 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 4278770f1..4a674c99e 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 19e89adf5..15221bb7d 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 410b42e00..e69de29bb 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 9fdbf158e..000000000 --- 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 3f54fccc6..454ca8f3c 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 7ce1785b6..e370acd7c 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 785b02e09..39dbb67d7 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -60,6 +60,7 @@ public: 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 000000000..47e2bfb76 --- /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 | 153 ++++++++++++++++++++---- test/libsolutil/IpfsHash.cpp | 53 ++++++-- 4 files changed, 178 insertions(+), 37 deletions(-) diff --git a/Changelog.md b/Changelog.md index 15221bb7d..e92b536df 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 49b17cf33..781f68d6b 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 d6a511a24..95605cdc1 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 4514b2f4c..9c4fb5633 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 15221bb7d..7dfb7a3e3 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 dd1e5136c..141a3eb32 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 af50b2722..1e851937c 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 889c21b6a..4f601a2d5 100644 --- a/libsolidity/formal/CHC.h +++ b/libsolidity/formal/CHC.h @@ -76,6 +76,7 @@ private: 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 @@ private: 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 3b2f48816..0efaf90a9 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 f49a572cf..290d73872 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 79acf49d7..f6e32d10a 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 5b339e004..79f0c03dc 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 c0bf299f8..d33247a0e 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 4ad9083fa..b5428d15b 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 6959f6c88..b6363f8ef 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 a607a9556..c4dbe0219 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 ee4504287..1f002796f 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 2647e0771..dd3924e29 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 d2f8ab1db..ee24f0ae5 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 d5b83f007..5d3292992 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 000000000..e17e384dd --- /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 000000000..3f765ecd2 --- /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 000000000..0d2a3c794 --- /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 000000000..da8dec6a2 --- /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 000000000..b052f5070 --- /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 000000000..cb50a931e --- /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 000000000..5e69f7830 --- /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 17cf6ea64..0c2a781fc 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 22b956584..00f78df3c 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 6959f6c88..b6363f8ef 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 82d411e47..7be0676d2 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 fc6643a42..ff316ce47 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 91798ec0c..36c8ce551 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 1fb380649..6303158f7 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 e7fde4d5a..ea1c54851 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 7f73f86c1..4b97a7ea0 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 e57c62313..11cd22d11 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 1a9216de0..0694493f5 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 c85e7e3fb..e022e0f29 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 e9752b3a8..986e7205b 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 4447cf6d7..71238c3be 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 7a420c28f..702c24f4b 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 b01fe812e..16d071fdb 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 9cd7de9e6..8a1ba5e6e 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 e9ef98b26..a8ae53997 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 1657a95c6..abee678c0 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 b2701fdf9..d94f3204b 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 8cd468652..00d2965bc 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 d015d1471..94e7ccfcf 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 f6d6b1977..1ae2b9356 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 6461634e1..2aacc5c0d 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 4b134e58e..3d60c836a 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 d70cc18bb..68438eb6d 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 13dc6fcc2..384a89b4f 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 ff47cc0e4..e94ad4580 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 062e9776d..dc69dd55a 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 1d5ab2687..2e16e7b5d 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 99e993032..dd846b483 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 fa0c5eae1..45c12263b 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 a675c29e2..7e31b10ae 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 c9c96a0a7..e2f597943 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 a1648c66e..9c1c3caaa 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 2bd2afbda..be1d40be4 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 47bdd0c66..4821518fd 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 000000000..bb2513790 --- /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 39d096f59..8170d67e6 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 86af187ad..f31192b3a 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 4a9291f89..afb9a9ea0 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 53b197395..8103a0203 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 1e548403d..e76db56d1 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 b125712fd..b1be75073 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 708e76339..758b11d92 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 000000000..880522d60 --- /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 a5d4aab67..492b0c754 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 5cf003bed..a9b2b5b9f 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 d903a1b4b..483b75301 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 7624080a9..af77b60f1 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 8b9061af3..21886faaf 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 000000000..fbd5ab6ee --- /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 000000000..563d47851 --- /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 6867f049c..8ea07f182 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 a9b2b5b9f..1345fbf90 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 6b03c7b58..a76e6e274 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 adb957cfe..052970bc8 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -879,6 +879,7 @@ public: 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 454ca8f3c..d760e0810 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 21886faaf..6fffbd5b5 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 0fc24d919..2b6285c0a 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 8da576055..9c7d9c8ac 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 e370acd7c..5a413a449 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 edf43377f..2f23c8c22 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 000000000..3636b0aef --- /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 000000000..7b98b67c6 --- /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 000000000..39f0f1e76 --- /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 000000000..7740f8643 --- /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 000000000..b4960f25b --- /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 000000000..67398ce20 --- /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 000000000..1c0e7a46f --- /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 709840bbc..0ed7c9881 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 63437da13..a65c95539 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 dcfb3e6bf..0afe95c6d 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 dfcf4a46b..aaa17525f 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 @@ public: 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 4af735d0b..557a1f74e 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 4791087b5..f281439bf 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 000000000..a1a955d57 --- /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 000000000..65a82eba4 --- /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 557a1f74e..eecaf6d3c 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 da6995e38..d78711634 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 000000000..16a4dd893 --- /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 0d32e9c1d..13a311669 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 f281439bf..58867e5b9 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 000000000..881f5b46e --- /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 000000000..ff436d73b --- /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 fa37ac5e3..432f3fe38 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 bab475c4e..b9ccb4302 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 @@ public: } }; - 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 @@ public: } }; - 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 a1a955d57..0a3e7f66e 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 65a82eba4..07b7426ab 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 16a4dd893..0270e4b83 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 881f5b46e..bd5ce5755 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 ff436d73b..c0aaa5621 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 0a3e7f66e..7708e85ba 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 bd5ce5755..0efe19b7c 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 | 128 ++++++++++++++++++++++++------------- tools/yulPhaser/Phaser.h | 88 ++++++++++++++++++++++++- 2 files changed, 168 insertions(+), 48 deletions(-) diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 7708e85ba..c03cf9369 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; + auto programOptions = ProgramFactory::Options::fromCommandLine(_arguments); + auto algorithmOptions = GeneticAlgorithmFactory::Options::fromCommandLine(_arguments); - CharStream sourceCode = loadSource(_sourcePath); - shared_ptr fitnessMetric = make_shared(Program::load(sourceCode), 5); - auto population = Population::makeRandom( - fitnessMetric, - populationSize, - minChromosomeLength, - maxChromosomeLength + 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 07b7426ab..1afd0836f 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 @@ private: 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 c03cf9369..ac96a1ee8 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 1afd0836f..750255576 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -131,12 +131,19 @@ public: 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 ac96a1ee8..c06533c21 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 c06533c21..ba99f3544 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 ba99f3544..45d9672d1 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 d78711634..14b8094a1 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 0270e4b83..f6102a9cb 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 23de34a2d..442f7967f 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 13a311669..f7a5e7a92 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 66852ed55..df58cec54 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 af03cd2bc..64109470f 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 2363256e4..7a9172749 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 7d9c81cd3..5c1d2a6e6 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 ce870ce80..02a85f4f3 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 f158fcbf6..0cdacc428 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 f9000921f..b52cee084 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 efc511a80..98d609050 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 14b8094a1..fa9127e72 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 000000000..e045a9a8c --- /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 58867e5b9..fb2d411b5 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 000000000..ae5b9ebd3 --- /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 e045a9a8c..891495193 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 ae5b9ebd3..9bf3f6204 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 45d9672d1..44fb9d130 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,32 +43,20 @@ 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); +map const AlgorithmToStringMap = +{ + {Algorithm::Random, "random"}, + {Algorithm::GEWEP, "GEWEP"}, +}; +map const StringToAlgorithmMap = invertMap(AlgorithmToStringMap); - 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; -} +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) { 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 2b6285c0a..d4f3d460d 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) { } + m_context << Instruction::SWAP3; + // stack: sliceEnd sliceStart length offset - 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::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 046769e43..ba664dbb6 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 cf50c785f..8841e98ad 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -175,6 +175,11 @@ public: /// 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 5a413a449..21a105db5 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 8e8a398de..7eb975677 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 000000000..d0e4ee595 --- /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 3bb71f35e..46901a46e 100644 --- a/libsolutil/vector_ref.h +++ b/libsolutil/vector_ref.h @@ -44,7 +44,6 @@ public: 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 66f1808ab..388bd4b56 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 dc32e2687..adee43296 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 93bfe48a9..c6fb28986 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 9dae37912..a912534ac 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 42cc8bf61..b4a6e4444 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 5e240e98d..c77ada9f2 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 58561806d..ecb628c6b 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 5c1d2a6e6..5d4e012f3 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 44fb9d130..cc093c9c8 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 b4a6e4444..f6bda59bd 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 c77ada9f2..6da9751b9 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 @@ public: 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 @@ private: 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 f6bda59bd..c397cd1f4 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 eecaf6d3c..0b56f0165 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 cc093c9c8..87bbb0eba 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 0b56f0165..1cfd310b7 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 ae75d19ef..1f675a9ef 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 87bbb0eba..4c2aff071 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 1cfd310b7..a567e355a 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 4c2aff071..6a7e7a88f 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 6a7e7a88f..5f0e3d87b 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 750255576..9ac6f81f0 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -128,7 +129,7 @@ private: class Phaser { public: - static int main(int argc, char** argv); + static void main(int argc, char** argv); private: struct CommandLineDescription @@ -137,14 +138,8 @@ private: 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 a567e355a..d0c00fcda 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 67c6d8810..34818889c 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 fa9127e72..00c682416 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 6d72ce010..ebc80dc2f 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 6b0a16e27..8b2afc780 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 d6afff8b8..b4e7e3972 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 @@ public: 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; - static std::string parseSimpleExpectations(std::istream& _file); + TestCase(std::string const& _filename): m_reader(_filename) {} + + 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 @@ protected: ++_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 000000000..2b7e201af --- /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 000000000..055b355b7 --- /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 3137a5085..5a76a3f18 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 1da0193ab..e7a0cce6d 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 b1b0d56f2..694839b99 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 912349182..f0bfed8d4 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 97c83a3e5..8b5112e12 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 0ea486cad..94c29e193 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -65,6 +65,7 @@ private: 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 1938cfe86..031a6085f 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 fdee56bda..a545b6124 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 2d74d5501..db3a39df0 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 f1b284042..9dd589748 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 75e38c844..8e5862b43 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(); + m_dialectName = m_reader.stringSetting("dialect", "evmTyped"); - if (!m_settings.count("dialect")) - return; - - string const dialect = m_settings["dialect"]; - m_validatedSettings["dialect"] = dialect; - m_settings.erase("dialect"); - - 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 087a6326c..8b4c24bd8 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -36,15 +36,13 @@ public: { 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 f37d18383..937ffb57e 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 e488460fc..c8cb601f1 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 41e38fca0..64e3cc83d 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -73,6 +73,7 @@ private: 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 5ea8486ec..c8add4ce7 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 e439aba64..da85c9ed0 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 ebc80dc2f..e3edc3fb0 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 22acd5413..e761e1487 100644 --- a/test/CommonSyntaxTest.h +++ b/test/CommonSyntaxTest.h @@ -73,7 +73,8 @@ protected: 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 fad5a127f..a1c23662a 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 f0bfed8d4..28c98ffab 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 031a6085f..3ec506998 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 ff1517eec..ee6d77dab 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 0b154e69c..b5f175ac2 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 8e5862b43..05accb695 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 8b4c24bd8..b4c838b54 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -42,7 +42,7 @@ protected: 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 c8cb601f1..6ab4b181f 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 72461f021..e7a43645c 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 a9ce0be92..00bca1f3b 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 95626bb2a..57ca62fec 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 aa784c6ad..2eb467acd 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 000000000..f5e33db4c --- /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 000000000..127aee556 --- /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 000000000..98d687f51 --- /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 000000000..1a159477a --- /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 000000000..efedd5b92 --- /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 000000000..5825b8a79 --- /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 d525a3f21..5c918de29 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 0c84c6d15..f0c1dd429 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 5f0e3d87b..f02e942f7 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 9ac6f81f0..20d9ace25 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -80,9 +80,15 @@ public: 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 f02e942f7..3d45db1e8 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 20d9ace25..ac6f70def 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include @@ -147,6 +149,7 @@ private: 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 3d45db1e8..768088e49 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 ac6f70def..4df0109f7 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -101,11 +101,22 @@ public: 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 768088e49..8c5fcbc26 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 4df0109f7..a12ccd87a 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -106,6 +106,7 @@ public: struct Options { + std::vector population; std::vector randomPopulation; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); @@ -115,6 +116,10 @@ public: 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 b52cee084..2379016fe 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 a59c7eed1..aa76ae6da 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 98d609050..7fc4ef0af 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 fa9127e72..d5bf4b686 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 891495193..39e6dd784 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 fb2d411b5..fd5f92bbe 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 000000000..aa7ba85b5 --- /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 9bf3f6204..c37afa2fb 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 1f675a9ef..e3a06fbed 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 8c5fcbc26..c8bc38a96 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 a12ccd87a..63f570594 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -108,6 +108,7 @@ public: { std::vector population; std::vector randomPopulation; + std::vector populationFromFile; static Options fromCommandLine(boost::program_options::variables_map const& _arguments); }; @@ -124,6 +125,10 @@ public: 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 f6102a9cb..7b20d8db4 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 @@ public: 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 @@ protected: 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 0efe19b7c..a075fa785 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 c0aaa5621..93c8348d5 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -42,6 +42,7 @@ public: struct Options { std::optional maxRounds = std::nullopt; + std::optional populationAutosaveFile = std::nullopt; }; AlgorithmRunner( @@ -59,6 +60,8 @@ public: 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 e3a06fbed..6807d7180 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 c8bc38a96..ee732298d 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 ee732298d..97e429968 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 63f570594..b45a9dd6e 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -64,15 +64,15 @@ public: 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 @@ public: 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 @@ public: ); 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 97e429968..b1ee03f56 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 b45a9dd6e..9631aa4cb 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -66,6 +66,13 @@ public: 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 7b20d8db4..0b54ad38f 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 a075fa785..b9f22171b 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 93c8348d5..ff0d0e3c3 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -43,6 +43,9 @@ public: { 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 @@ public: 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 b1ee03f56..e8902a1bc 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 e8902a1bc..7640fbf28 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 7fac5f080..95608e89b 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -57,6 +57,9 @@ public: 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 b9ccb4302..a2a7484d6 100644 --- a/tools/yulPhaser/GeneticAlgorithms.h +++ b/tools/yulPhaser/GeneticAlgorithms.h @@ -81,6 +81,8 @@ public: assert(_options.isValid()); } + Options const& options() const { return m_options; } + Population runNextRound(Population _population) override; private: @@ -129,6 +131,8 @@ public: 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 d5bf4b686..7165a5e27 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 000000000..26fe3c55e --- /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 ecb628c6b..e7a389be7 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 @@ protected: " 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}); + size_t fitness = ProgramSize(m_program).evaluate(m_chromosome); - Program optimisedProgram = m_program; - optimisedProgram.optimise(chromosome.optimisationSteps()); - assert(m_program.codeSize() != optimisedProgram.codeSize()); - - 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 e7a389be7..293fac426 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 @@ protected: 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 be7ea5497..a3a344eb9 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 95608e89b..180fa322c 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -47,24 +47,44 @@ public: }; /** - * 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 293fac426..8e4b14185 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 aa76ae6da..2bf755b18 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 a3a344eb9..0992b9be0 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 180fa322c..b50c26c8e 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -43,7 +43,7 @@ public: 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 ec63eb3bb..87df4e59b 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 29c82efed..f8f12632e 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 @@ public: ) {} 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 @@ public: 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 @@ public: 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 8e4b14185..27997c791 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 0992b9be0..02c3b457f 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 b50c26c8e..3544dba75 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -87,4 +87,30 @@ public: 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 27997c791..8b62b03b7 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -78,6 +78,21 @@ protected: 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 02c3b457f..49482d0af 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 3544dba75..e79d99ff4 100644 --- a/tools/yulPhaser/FitnessMetrics.h +++ b/tools/yulPhaser/FitnessMetrics.h @@ -113,4 +113,60 @@ private: 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 26fe3c55e..a99c464da 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -61,6 +61,7 @@ protected: 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 7640fbf28..e8f2cae50 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 9631aa4cb..effa2ffe6 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 a99c464da..800301ecf 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -62,6 +62,7 @@ protected: 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 e8f2cae50..a0a787f7f 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 effa2ffe6..07f1eaea1 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -100,6 +100,7 @@ public: 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 800301ecf..ea06dd771 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -58,8 +58,16 @@ protected: 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 a0a787f7f..d0d9d9a1e 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 07f1eaea1..55c808f07 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -108,7 +108,7 @@ public: 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 ea06dd771..aab34db61 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -70,6 +70,7 @@ protected: }; 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 d0d9d9a1e..c62b62dc3 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 55c808f07..2e72c31f6 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 @@ public: 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 c62b62dc3..da0296eff 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 | 6372 +---------------- .../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, 6021 insertions(+), 6362 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 2c3dfebac..ae39bec0e 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,221 +1753,6 @@ BOOST_AUTO_TEST_CASE(blockhash) ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes)); } -BOOST_AUTO_TEST_CASE(value_complex) -{ - 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)(); - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); -} - -BOOST_AUTO_TEST_CASE(value_insane) -{ - 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 returns (uint256 bal) { - return h.getBalance.value(amount).gas(1000).value(amount + 3)();// overwrite value - } - } - )"; - compileAndRun(sourceCode, 20); - BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(8)); -} - -BOOST_AUTO_TEST_CASE(value_for_constructor) -{ - 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); - } - 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)); -} - -BOOST_AUTO_TEST_CASE(virtual_function_calls) -{ - 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; } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(2)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(2)); - ) -} - -BOOST_AUTO_TEST_CASE(access_base_storage) -{ - 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; - } - } - )"; - 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)); - ) -} - -BOOST_AUTO_TEST_CASE(explicit_base_class) -{ - 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; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(3)); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(base_constructor_arguments) -{ - 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 Derived is Base() { - function getA() public returns (uint r) { return m_a; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(7 * 7)); -} - -BOOST_AUTO_TEST_CASE(function_usage_in_constructor_arguments) -{ - 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 Base is BaseBase(BaseBase.g()) { - } - contract Derived is Base() { - function getA() public returns (uint r) { return m_a; } - } - )"; - compileAndRun(sourceCode, 0, "Derived"); - ABI_CHECK(callContractFunction("getA()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(virtual_function_usage_in_constructor_arguments) -{ - char const* sourceCode = R"( - contract BaseBase { - uint m_a; - constructor(uint a) public { - m_a = a; - } - 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)); -} - BOOST_AUTO_TEST_CASE(internal_constructor) { char const* sourceCode = R"( @@ -2191,260 +1763,6 @@ BOOST_AUTO_TEST_CASE(internal_constructor) BOOST_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "C").empty()); } -BOOST_AUTO_TEST_CASE(function_modifier) -{ - char const* sourceCode = R"( - contract C { - function getOne() payable nonFree public returns (uint r) { return 1; } - modifier nonFree { if (msg.value > 0) _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getOne()"), encodeArgs(0)); - ABI_CHECK(callContractFunctionWithValue("getOne()", 1), encodeArgs(1)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_local_variables) -{ - 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; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(0)); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_loop) -{ - 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; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(10)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation) -{ - char const* sourceCode = R"( - contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return) -{ - // Note that return sets the return variable and jumps to the end of the current function or - // modifier code block. - char const* sourceCode = R"( - contract C { - modifier repeat(bool twice) { if (twice) _; _; } - function f(bool twice) repeat(twice) public returns (uint r) { r += 1; return r; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(bool)", false), encodeArgs(1)); - ABI_CHECK(callContractFunction("f(bool)", true), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_overriding) -{ - 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) _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(false)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context) -{ - 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; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(0x4300)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_for_constructor) -{ - 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; _; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("getData()"), encodeArgs(4 | 2)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times) -{ - char const* sourceCode = R"( - 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; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(2 + 5 + 3)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_multiple_times_local_vars) -{ - 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; } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint256)", u256(3)), encodeArgs(2 + 5 + 3)); - ABI_CHECK(callContractFunction("a()"), encodeArgs(0)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_library) -{ - 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; - - function f() public returns (uint) { - s.libFun(); - L.libFun(s); - return s.v; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); -} - -BOOST_AUTO_TEST_CASE(function_modifier_library_inheritance) -{ - // 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; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(0x202)); -} - -BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - uint; uint; uint; uint; - int x = -7; - return uint(x); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(-7))); - ) -} - -BOOST_AUTO_TEST_CASE(super) -{ - 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; } } - )"; - compileAndRun(sourceCode, 0, "D"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1 | 2 | 4 | 8)); -} - -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)); -} - -BOOST_AUTO_TEST_CASE(super_alone) -{ - 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( @@ -3085,62 +2403,6 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) ) } -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"( @@ -3211,24 +2473,6 @@ BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments_with_string_literals) )); } -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( @@ -3414,7 +2658,6 @@ BOOST_AUTO_TEST_CASE(library_call_protection) ABI_CHECK(callContractFunction("pu()"), encodeArgs(2)); } - BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) { char const* sourceCode = R"( @@ -3439,25 +2682,6 @@ BOOST_AUTO_TEST_CASE(library_staticcall_delegatecall) 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"( @@ -3655,61 +2879,6 @@ BOOST_AUTO_TEST_CASE(bytes_inside_mappings) 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"( @@ -3746,84 +2915,6 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) 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"( @@ -3867,75 +2958,6 @@ BOOST_AUTO_TEST_CASE(storing_invalid_boolean) 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"( @@ -4042,80 +3064,6 @@ BOOST_AUTO_TEST_CASE(enum_referencing) 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"( @@ -4174,93 +3122,6 @@ BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) 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"( @@ -4390,103 +3251,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) 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 @@ -4510,41 +3274,7 @@ BOOST_AUTO_TEST_CASE(array_copy_target_leftover) } )"; 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")) - )); + ABI_CHECK(callContractFunction("test()"), encodeArgs(u256("0xffffffff"), asString(fromHex("0000000000000000000000000a00090008000700060005000400030002000100")), asString(fromHex("0000000000000000000000000000000000000000000000000000000000000000")))); } BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) @@ -4625,167 +3355,6 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi) ); } -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"( @@ -4872,21 +3441,6 @@ BOOST_AUTO_TEST_CASE(array_pop_array_transition) 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"( @@ -4903,45 +3457,6 @@ BOOST_AUTO_TEST_CASE(array_pop_storage_empty) 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"( @@ -5011,84 +3526,6 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) 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"( @@ -5149,26 +3586,6 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) 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"( @@ -5194,42 +3611,8 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) } )"; 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)); + 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(array_copy_including_mapping) @@ -5279,145 +3662,6 @@ BOOST_AUTO_TEST_CASE(array_copy_including_mapping) 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"( @@ -5458,98 +3702,6 @@ BOOST_AUTO_TEST_CASE(assignment_to_const_var_involving_keccak) // 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"( @@ -5581,118 +3733,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) 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"( @@ -5722,81 +3762,6 @@ BOOST_AUTO_TEST_CASE(bool_conversion) 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"( @@ -5831,230 +3796,6 @@ BOOST_AUTO_TEST_CASE(invalid_enum_logged) 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"( @@ -6073,21 +3814,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) 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"( @@ -6111,27 +3837,6 @@ BOOST_AUTO_TEST_CASE(failing_send) 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. @@ -6463,23 +4168,6 @@ BOOST_AUTO_TEST_CASE(arrays_in_constructors) ); } -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"( @@ -6584,61 +4272,6 @@ BOOST_AUTO_TEST_CASE(bytes_memory_index_access) ); } -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"( @@ -6738,111 +4371,6 @@ BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) 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"( @@ -6917,207 +4445,6 @@ BOOST_AUTO_TEST_CASE(struct_constructor_nested) 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"( @@ -7238,25 +4565,6 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_bytes) ); } -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"( @@ -7481,70 +4789,6 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional) } } -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"( @@ -7591,29 +4835,6 @@ BOOST_AUTO_TEST_CASE(initialise_string_constant) 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"( @@ -7629,13 +4850,7 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion) } )"; compileAndRun(sourceCode, 0, "Test"); - ABI_CHECK(callContractFunction( - "f(string,uint256)", - u256(0x40), - u256(2), - u256(6), - string("abcdef") - ), encodeArgs("c")); + ABI_CHECK(callContractFunction("f(string,uint256)", u256(0x40), u256(2), u256(6), string("abcdef")), encodeArgs("c")); ABI_CHECK(callContractFunction("l()"), encodeArgs(u256(6))); } @@ -7814,162 +5029,6 @@ BOOST_AUTO_TEST_CASE(nested_mixed_string_as_public_mapping_key) ), 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"( @@ -8002,21 +5061,6 @@ BOOST_AUTO_TEST_CASE(constant_string_literal) 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"( @@ -8064,39 +5108,6 @@ BOOST_AUTO_TEST_CASE(library_stray_values) 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"( @@ -8139,35 +5150,6 @@ BOOST_AUTO_TEST_CASE(strings_in_struct) 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"( @@ -8470,48 +5452,6 @@ BOOST_AUTO_TEST_CASE(using_library_structs) 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 @@ -8649,16 +5589,6 @@ BOOST_AUTO_TEST_CASE(calldata_offset) 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"( @@ -8684,234 +5614,6 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library) 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)); -} - -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)); -} - -BOOST_AUTO_TEST_CASE(tuples) -{ - 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; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(string_tuples) -{ - 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"); - } - } - )"; - 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; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(inline_tuple_with_rational_numbers) -{ - char const* sourceCode = R"( - contract c { - function f() public returns (int8) { - int8[5] memory foo3 = [int8(1), -1, 0, 0, 0]; - return foo3[0]; - } - } - )"; - 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; - } - } - )"; - 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))); - ) -} - -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"))); -} - BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) { // Check allocation size of byte array. Should be 32 plus length rounded up to next @@ -8939,145 +5641,6 @@ BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size) } } -BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes) -{ - // 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]; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(create_multiple_dynamic_arrays) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(memory_overwrite) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (bytes memory x) { - x = "12345"; - x[3] = 0x61; - x[0] = 0x62; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeDyn(string("b23a5"))); -} - -BOOST_AUTO_TEST_CASE(addmod_mulmod) -{ - 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; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(addmod_mulmod_zero) -{ - char const* sourceCode = R"( - contract C { - function f(uint d) public pure returns (uint) { - addmod(1, 2, d); - return 2; - } - function g(uint d) public pure returns (uint) { - mulmod(1, 2, d); - return 2; - } - function h() public pure returns (uint) { - mulmod(0, 1, 2); - mulmod(1, 0, 2); - addmod(0, 1, 2); - addmod(1, 0, 2); - return 2; - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("g(uint)", 0), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(2)); -} - -BOOST_AUTO_TEST_CASE(divisiod_by_zero) -{ - 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; - } - } - )"; - 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()); -} - BOOST_AUTO_TEST_CASE(string_allocation_bug) { char const* sourceCode = R"( @@ -9096,16 +5659,7 @@ BOOST_AUTO_TEST_CASE(string_allocation_bug) } )"; 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("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) @@ -9246,119 +5800,6 @@ BOOST_AUTO_TEST_CASE(bound_function_to_string) ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(3))); } -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_strings) -{ - 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]); - } - } - )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x40), u256(0x80), u256(3), string("ray"), u256(2), string("mi"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_strings_from_document) -{ - 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]); - } - } - )"; - 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"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_ints) -{ - 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]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3, 6)); -} - -BOOST_AUTO_TEST_CASE(inline_array_index_access_ints) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - return ([1, 2, 3, 4][2]); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(3)); -} - -BOOST_AUTO_TEST_CASE(inline_array_index_access_strings) -{ - char const* sourceCode = R"( - contract C { - string public tester; - function f() public returns (string memory) { - return (["abc", "def", "g"][0]); - } - function test() public { - tester = f(); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - ABI_CHECK(callContractFunction("tester()"), encodeArgs(u256(0x20), u256(3), string("abc"))); -} - -BOOST_AUTO_TEST_CASE(inline_array_return) -{ - 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]); - } - - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(1, 2, 3, 4, 5)); -} - -BOOST_AUTO_TEST_CASE(inline_array_singleton) -{ - // 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]; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(4))); -} - BOOST_AUTO_TEST_CASE(inline_long_string_return) { char const* sourceCode = R"( @@ -9395,404 +5836,6 @@ BOOST_AUTO_TEST_CASE(fixed_bytes_index_access) ABI_CHECK(callContractFunction("data(uint256)", u256(1)), encodeArgs("8")); } -BOOST_AUTO_TEST_CASE(fixed_bytes_length_access) -{ - 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); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(bytes32)", "789"), encodeArgs(u256(32), u256(16), u256(8))); -} - -BOOST_AUTO_TEST_CASE(byte_optimization_bug) -{ - char const* sourceCode = R"( - contract C { - function f(uint x) public returns (uint a) { - assembly { - a := byte(x, 31) - } - } - function g(uint x) public returns (uint a) { - assembly { - a := byte(31, x) - } - } - } - )"; - 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))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_write_to_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r, bytes32 r2) { - assembly { r := 7 r2 := "abcdef" } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7), string("abcdef"))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_read_and_write_stack) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint r) { - for (uint x = 0; x < 10; ++x) - assembly { r := add(r, x) } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(45))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_memory_access) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0x20), u256(5), string("12345"))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_inside_function) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); - ABI_CHECK(callContractFunction("z()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_via_pointer) -{ - 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 - } - 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))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call) -{ - char const* sourceCode = R"( - 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) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment) -{ - 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) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_function_call2) -{ - 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) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(2), u256(7), u256(0x10))); - ) -} - -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) - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(4), u256(7), u256(0x10))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_if) -{ - char const* sourceCode = R"( - contract C { - function f(uint a) public returns (uint b) { - assembly { - if gt(a, 1) { b := 2 } - } - } - } - )"; - 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))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_switch) -{ - 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 } - } - } - } - )"; - 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))); - ) -} - -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) - } - } - } - )"; - 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))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_for) -{ - 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) - } - } - } - )"; - 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))); - ) -} - -BOOST_AUTO_TEST_CASE(inline_assembly_for2) -{ - 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; - } - } - )"; - 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. @@ -9809,152 +5852,6 @@ BOOST_AUTO_TEST_CASE(index_access_with_type_conversion) BOOST_CHECK(callContractFunction("f(uint256)", u256(0x101)).size() == 256 * 32); } -BOOST_AUTO_TEST_CASE(delete_on_array_of_structs) -{ - // 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; - } - } - )"; - 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)); - -} - -BOOST_AUTO_TEST_CASE(internal_library_function) -{ - // 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]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_calling_private) -{ - // 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]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_bound) -{ - char const* sourceCode = R"( - library L { - struct S { uint[] data; } - function f(S memory _s) internal { - _s.data[3] = 2; - } - } - 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]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(internal_library_function_return_var_size) -{ - 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 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]; - } - } - )"; - // This has to work without linking, because everything will be inlined. - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); -} - -BOOST_AUTO_TEST_CASE(iszero_bnot_correct) -{ - // 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(cleanup_bytes_types) { // Checks that bytesXX types are properly cleaned before they are compared. @@ -9973,23 +5870,6 @@ BOOST_AUTO_TEST_CASE(cleanup_bytes_types) 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_bytes_types_shortening) -{ - 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)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs("\xff\xff\xff\xff")); -} BOOST_AUTO_TEST_CASE(cleanup_address_types) { // Checks that address types are properly cleaned before they are compared. @@ -10013,80 +5893,6 @@ BOOST_AUTO_TEST_CASE(cleanup_address_types) ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), v2 ? encodeArgs() : encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening) -{ - 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); - } - 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); - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256("0x1122334455667788990011223344556677889900"))); - ) -} - -BOOST_AUTO_TEST_CASE(skip_dynamic_types) -{ - // 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); - } - 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); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(7), u256(8))); -} - -BOOST_AUTO_TEST_CASE(skip_dynamic_types_for_structs) -{ - // 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); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(2), u256(6))); -} - BOOST_AUTO_TEST_CASE(failed_create) { char const* sourceCode = R"( @@ -10115,20 +5921,6 @@ BOOST_AUTO_TEST_CASE(failed_create) ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); } -BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint) { - uint[][] memory a = new uint[][](0); - return 7; - } - } - )"; - 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. @@ -10159,122 +5951,6 @@ BOOST_AUTO_TEST_CASE(correctly_initialize_memory_array_in_constructor) } } -BOOST_AUTO_TEST_CASE(return_does_not_skip_modifier) -{ - char const* sourceCode = R"( - contract C { - uint public x; - modifier setsx { - _; - x = 9; - } - function f() setsx public returns (uint) { - return 2; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(break_in_modifier) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(continue_in_modifier) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(5))); -} - -BOOST_AUTO_TEST_CASE(return_in_modifier) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(stacked_return_with_modifiers) -{ - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0))); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1))); -} - BOOST_AUTO_TEST_CASE(mutex) { char const* sourceCode = R"( @@ -10344,44 +6020,6 @@ BOOST_AUTO_TEST_CASE(mutex) BOOST_CHECK_EQUAL(balanceAt(fund), 460); } -BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws) -{ - 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; - } - function h() public returns (uint) { - address(d).call(""); // this does not throw (low-level) - return 7; - } - } - )YY"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ABI_CHECK(callContractFunction("g()"), encodeArgs()); - ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(payable_constructor) -{ - char const* sourceCode = R"( - contract C { - constructor() public payable { } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 27, "C"); - ) -} - BOOST_AUTO_TEST_CASE(payable_function) { char const* sourceCode = R"( @@ -10496,111 +6134,6 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) ABI_CHECK(callContractFunction("f(address)", cAddr), encodeArgs(u256(7))); } -BOOST_AUTO_TEST_CASE(calling_uninitialized_function) -{ - char const* sourceCode = R"( - contract C { - function intern() public returns (uint) { - function (uint) internal returns (uint) x; - x(2); - return 7; - } - function extern() public returns (uint) { - function (uint) external returns (uint) x; - x(2); - return 7; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - // This should throw exceptions - ABI_CHECK(callContractFunction("intern()"), encodeArgs()); - ABI_CHECK(callContractFunction("extern()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail) -{ - char const* sourceCode = R"( - 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; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(calling_uninitialized_function_through_array) -{ - char const* sourceCode = R"( - 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; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs()); -} - -BOOST_AUTO_TEST_CASE(pass_function_types_internally) -{ - char const* sourceCode = R"( - 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 g(uint x) public returns (uint) { return x + 1; } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256)", 7), encodeArgs(u256(8))); -} - -BOOST_AUTO_TEST_CASE(pass_function_types_externally) -{ - 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); - } - function eval(function(uint) external returns (uint) x, uint a) public returns (uint) { - return x(a); - } - 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("f2(uint256)", 7), encodeArgs(u256(8))); -} - BOOST_AUTO_TEST_CASE(receive_external_function_type) { char const* sourceCode = R"( @@ -10637,615 +6170,8 @@ BOOST_AUTO_TEST_CASE(return_external_function_type) ); } -BOOST_AUTO_TEST_CASE(store_function) -{ - 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); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(9))); -} - -BOOST_AUTO_TEST_CASE(store_function_in_constructor) -{ - 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); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("result_in_constructor()"), encodeArgs(u256(4))); -} - // TODO: store bound internal library functions -BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor) -{ - 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(); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor) -{ - 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(); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("t()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime) -{ - 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); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))), encodeArgs(u256(6))); - ABI_CHECK(callContractFunction("initial()"), encodeArgs(u256(4))); -} - -BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check) -{ - char const* sourceCode = R"( - contract C { - function (uint) internal returns (uint) x; - constructor() public { - x = double; - } - function test() public returns (bool) { - return x == double; - } - function double(uint _arg) public returns (uint _ret) { - _ret = _arg * 2; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); -} - -BOOST_AUTO_TEST_CASE(function_type_library_internal) -{ - 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); - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)), encodeArgs(u256(11))); -} - - -BOOST_AUTO_TEST_CASE(call_function_returning_function) -{ - 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()()()(); - } - } - )"; - - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "test"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2))); - ) -} - -BOOST_AUTO_TEST_CASE(mapping_of_functions) -{ - 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; - } - } - )"; - - 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)); -} - -BOOST_AUTO_TEST_CASE(packed_functions) -{ - 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; - - function set() public { - x = 2; - d = g; - c = this.h; - b = this.h; - a = g; - } - function t1() public returns (uint) { - return a(); - } - function t2() public returns (uint) { - return b(); - } - function t3() public returns (uint) { - return a(); - } - function t4() public returns (uint) { - return b(); - } - function g() public returns (uint) { - return 7; - } - function h() public returns (uint) { - return 8; - } - } - )"; - - 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))); -} - -BOOST_AUTO_TEST_CASE(function_memory_array) -{ - 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); - } - } - )"; - - 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()); -} - -BOOST_AUTO_TEST_CASE(function_delete_storage) -{ - 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(); - } - function d() public returns (uint) { - delete y; - return 1; - } - function ca() public returns (uint) { - return y(); - } - } - )"; - - 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()); -} - -BOOST_AUTO_TEST_CASE(function_delete_stack) -{ - 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(); - } - } - )"; - - 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](); - } - function a() public returns (uint) { - return 7; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(7))); -} - -BOOST_AUTO_TEST_CASE(function_array_cross_calls) -{ - 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) - { - r[0] = x[0](); - r[1] = x[1](); - r[2] = x[2](); - } - } - 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; - } - function htwo() public returns (function() external returns (uint)) { - return this.e; - } - } - )"; - - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(5), u256(6), u256(7))); -} - -BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage) -{ - 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; - } - 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; - } - } - )"; - - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_negative_constant_left) -{ - char const* sourceCode = R"( - contract C { - int public a = -0x42 << 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(-0x4200))); -} - -BOOST_AUTO_TEST_CASE(shift_constant_right) -{ - char const* sourceCode = R"( - contract C { - uint public a = 0x4200 >> 8; - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_negative_constant_right) -{ - char const* sourceCode = R"( - contract C { - int public a = -0x4200 >> 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; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_left_uint32) -{ - char const* sourceCode = R"( - contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a << b; - } - } - )"; - 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; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_left_larger_type) -{ - // This basically tests proper cleanup and conversion. It should not convert x to int8. - char const* sourceCode = R"( - contract C { - function f() public returns (int8) { - uint8 x = 254; - int8 y = 1; - return y << x; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0))); -} - -BOOST_AUTO_TEST_CASE(shift_left_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - a <<= b; - return 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(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))); -} - -BOOST_AUTO_TEST_CASE(shift_left_assignment_different_type) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint8 b) public returns (uint) { - a <<= b; - return a; - } - } - )"; - 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")); -} - -BOOST_AUTO_TEST_CASE(shift_right) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - return a >> b; - } - } - )"; - 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)); -} - BOOST_AUTO_TEST_CASE(shift_right_garbled) { char const* sourceCode = R"( @@ -11299,177 +6225,6 @@ BOOST_AUTO_TEST_CASE(shift_right_garbled_signed) ABI_CHECK(callContractFunction("g(int8,uint8)", u256(0x0), u256(0x1004)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } -BOOST_AUTO_TEST_CASE(shift_right_uint32) -{ - char const* sourceCode = R"( - contract C { - function f(uint32 a, uint32 b) public returns (uint) { - return a >> b; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_right_uint8) -{ - char const* sourceCode = R"( - contract C { - function f(uint8 a, uint8 b) public returns (uint) { - return a >> b; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_right_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(uint a, uint b) public returns (uint) { - a >>= b; - return 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))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - return a >> b; - } - } - )"; - 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"( @@ -11524,198 +6279,6 @@ BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_signextend_int32) ABI_CHECK(callContractFunction("f(int32,int32)", u256(0xFFFFFF99u), u256(8)), v2 ? encodeArgs() : encodeArgs(u256(-1))); } - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int16) -{ - char const* sourceCode = R"( - contract C { - function f(int16 a, int16 b) public returns (int) { - return a >> b; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_int32) -{ - char const* sourceCode = R"( - contract C { - function f(int32 a, int32 b) public returns (int) { - return a >> b; - } - } - )"; - 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))); -} - -BOOST_AUTO_TEST_CASE(shift_right_negative_lvalue_assignment) -{ - 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(-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_negative_rvalue) -{ - 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; - } - } - )"; - 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()); -} - -BOOST_AUTO_TEST_CASE(shift_negative_rvalue_assignment) -{ - char const* sourceCode = R"( - contract C { - function f(int a, int b) public returns (int) { - a <<= b; - return a; - } - function g(int a, int b) public returns (int) { - a >>= b; - return a; - } - } - )"; - 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()); -} - -BOOST_AUTO_TEST_CASE(shift_constant_left_assignment) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint a) { - a = 0x42; - a <<= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x4200))); -} - -BOOST_AUTO_TEST_CASE(shift_constant_right_assignment) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint a) { - a = 0x4200; - a >>= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x42))); -} - -BOOST_AUTO_TEST_CASE(shift_cleanup) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint16 x) { - x = 0xffff; - x += 32; - x <<= 8; - x >>= 16; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); -} - -BOOST_AUTO_TEST_CASE(shift_cleanup_garbled) -{ - char const* sourceCode = R"( - contract C { - function f() public returns (uint8 x) { - assembly { - x := 0xffff - } - x >>= 8; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x0))); -} - -BOOST_AUTO_TEST_CASE(shift_overflow) -{ - char const* sourceCode = R"( - 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; - } - } - )"; - 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))); -} - BOOST_AUTO_TEST_CASE(shift_bytes) { char const* sourceCode = R"( @@ -11754,108 +6317,6 @@ BOOST_AUTO_TEST_CASE(shift_bytes_cleanup) ABI_CHECK(callContractFunction("right(uint8)", 8 * 8), encodeArgs(string(8, 0) + "123456789012")); } -BOOST_AUTO_TEST_CASE(exp_cleanup) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - uint8 y = uint8(2) ** uint8(8); - return 0 ** y; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(exp_cleanup_direct) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - return uint8(0) ** uint8(uint8(2) ** uint8(8)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(exp_cleanup_nonzero_base) -{ - char const* sourceCode = R"( - contract C { - function f() public pure returns (uint8 x) { - return uint8(0x166) ** uint8(uint8(2) ** uint8(8)); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1))); -} - -BOOST_AUTO_TEST_CASE(cleanup_in_compound_assign) -{ - 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); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("test()"), encodeArgs(u256(0xff), u256(0xff))); -} - -BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers) -{ - char const* sourceCode = R"( - contract C { - modifier m { - uint a = 1; - assembly { - a := 2 - } - 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)); - ) -} - -BOOST_AUTO_TEST_CASE(packed_storage_overflow) -{ - 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); - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe))); -} - BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) { char const* sourceCode = R"( @@ -11870,7 +6331,6 @@ BOOST_AUTO_TEST_CASE(contracts_separated_with_comment) ) } - BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) { char const* sourceCode = R"( @@ -11900,97 +6360,6 @@ BOOST_AUTO_TEST_CASE(include_creation_bytecode_only_once) ); } -BOOST_AUTO_TEST_CASE(recursive_structs) -{ - char const* sourceCode = R"( - contract C { - struct S { - S[] x; - } - 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; - } - } - )"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); -} - -BOOST_AUTO_TEST_CASE(invalid_instruction) -{ - char const* sourceCode = R"( - contract C { - function f() public { - assembly { - invalid() - } - } - } - )"; - ALSO_VIA_YUL( - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs()); - ) -} - -BOOST_AUTO_TEST_CASE(assert_require) -{ - 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; - } - } - )"; - 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)); - ) -} - -BOOST_AUTO_TEST_CASE(revert) -{ - char const* sourceCode = R"( - contract C { - uint public a = 42; - function f() public { - a = 1; - revert(); - } - function g() public { - a = 1; - assembly { - revert(0, 0) - } - } - } - )"; - 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))); -} - BOOST_AUTO_TEST_CASE(revert_with_cause) { char const* sourceCode = R"( @@ -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"( @@ -13401,88 +7512,6 @@ BOOST_AUTO_TEST_CASE(abi_encode_empty_string) } } -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( - 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; - } - } - )T"; - compileAndRun(sourceCode, 0, "C"); - ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) { char const* sourceCode = R"( @@ -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 000000000..180d89ec1 --- /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 000000000..270a5abc0 --- /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 000000000..46450f704 --- /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 000000000..7b873951f --- /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 000000000..1dbf320bd --- /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 000000000..a5e7a9af8 --- /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 000000000..95b667e47 --- /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 000000000..ac17cf80e --- /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 000000000..d73db5da6 --- /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 000000000..1fbcfa53d --- /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 000000000..373334ee7 --- /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 000000000..704fd54dc --- /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 000000000..55047880a --- /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 000000000..f6510b53d --- /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 000000000..a083ccd98 --- /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 000000000..a9402aa86 --- /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 000000000..e2b59b530 --- /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 000000000..d1e9f5c20 --- /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 000000000..7585980e1 --- /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 000000000..9b68cc154 --- /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 000000000..f0afcffc9 --- /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 000000000..9330d3162 --- /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 000000000..0e225f1e5 --- /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 000000000..4432776fb --- /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 000000000..71601d477 --- /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 000000000..1bbd95f6f --- /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 000000000..ab82589c2 --- /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 000000000..5667b61d4 --- /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 000000000..8fc018d72 --- /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 000000000..2e6eac83e --- /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 000000000..bd8200a37 --- /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 000000000..dd5e2e855 --- /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 000000000..e407fc025 --- /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 000000000..6bd146a7a --- /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 000000000..b83b1c598 --- /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 000000000..d6a80dbf9 --- /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 000000000..753e9bd1e --- /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 000000000..2384c061f --- /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 000000000..1d1036c2c --- /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 000000000..5ed849702 --- /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 000000000..2589f1f55 --- /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 000000000..30ffa3a4c --- /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 000000000..a9e3fd383 --- /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 000000000..1f6d500bd --- /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 000000000..67ed87b69 --- /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 000000000..ceecf6726 --- /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 000000000..3d94e4333 --- /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 000000000..e3a8ec19d --- /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 000000000..8c4872017 --- /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 000000000..5d93ba0ee --- /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 000000000..c9c6dbda0 --- /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 000000000..d643d3973 --- /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 000000000..3efd177b2 --- /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 000000000..333112265 --- /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 000000000..f408746f5 --- /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 000000000..7b225a33b --- /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 000000000..a7ecf2bd0 --- /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 000000000..c3b8249e8 --- /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 000000000..3e8613fad --- /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 000000000..db8171a20 --- /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 000000000..4139c1073 --- /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 000000000..2ccfc064c --- /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 000000000..e1cab8fe8 --- /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 000000000..0ae431b24 --- /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 000000000..26a2a79f4 --- /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 000000000..074b3ff6b --- /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 000000000..dc7c7f890 --- /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 000000000..c1901c738 --- /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 000000000..2c115d6c8 --- /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 000000000..3fbcf6132 --- /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 000000000..ecad28a16 --- /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 000000000..56cbf982d --- /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 000000000..017de5d7b --- /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 000000000..98b4773c7 --- /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 000000000..9ff75fad6 --- /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 000000000..ec30bacf6 --- /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 000000000..756478e34 --- /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 000000000..10243f897 --- /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 000000000..1db0f2e9f --- /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 000000000..f1220d351 --- /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 000000000..eba61ad1a --- /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 000000000..076cbbf69 --- /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 000000000..fdd7aa32e --- /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 000000000..7c2ccde6e --- /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 000000000..fd4fe943c --- /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 000000000..731fb4312 --- /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 000000000..47842cc03 --- /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 000000000..b00942cb3 --- /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 000000000..316b8d9ef --- /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 000000000..5628501d9 --- /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 000000000..949024f43 --- /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 000000000..0c8dc3835 --- /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 000000000..127320fc6 --- /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 000000000..6680ec5d9 --- /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 000000000..b2c6893a5 --- /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 000000000..d1ea9ab34 --- /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 000000000..fd4c96ce7 --- /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 000000000..2192dabf3 --- /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 000000000..af14b48b4 --- /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 000000000..a81e2755e --- /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 000000000..a9b5e81b5 --- /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 000000000..4f817d186 --- /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 000000000..44553b3f1 --- /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 000000000..362586447 --- /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 000000000..7909f8e32 --- /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 000000000..9906bd52b --- /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 000000000..61d1a33f5 --- /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 000000000..ff13db5be --- /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 000000000..7a6afbae7 --- /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 000000000..06246cdc6 --- /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 000000000..8309615a5 --- /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 000000000..64f8c7402 --- /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 000000000..96a66fce2 --- /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 000000000..6c7ecf4f6 --- /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 000000000..cc6b3cf46 --- /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 000000000..fcb8f64a2 --- /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 000000000..f4a73ebeb --- /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 000000000..ac99b0cf7 --- /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 000000000..f10ebb0e7 --- /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 000000000..3d5e97de0 --- /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 000000000..1df8b0874 --- /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 000000000..0c4c07828 --- /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 000000000..124e15970 --- /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 000000000..286476820 --- /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 000000000..722334ec9 --- /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 000000000..64354ba5e --- /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 000000000..c91869615 --- /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 000000000..f096a4979 --- /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 000000000..e92a37b19 --- /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 000000000..42db8582a --- /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 000000000..aaafb6f28 --- /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 000000000..dbd524deb --- /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 000000000..8de56296e --- /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 000000000..00c0eabed --- /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 000000000..e25db0dcb --- /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 000000000..23f9bee37 --- /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 000000000..9812ca520 --- /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 000000000..0fd02e8f3 --- /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 000000000..9a2c1a1e7 --- /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 000000000..42d4f711c --- /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 000000000..8dc5a7451 --- /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 000000000..19dfcf3b7 --- /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 000000000..e247d1558 --- /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 000000000..5925aba0f --- /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 000000000..f3f37ea20 --- /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 000000000..fa9f24a7a --- /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 000000000..ebcae638a --- /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 000000000..3d31c1add --- /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 000000000..451ecbbe5 --- /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 000000000..2c05f1556 --- /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 000000000..17a271d5b --- /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 000000000..26d3d43b7 --- /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 000000000..2dec9761b --- /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 000000000..9f94f3c19 --- /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 000000000..3c9f3a2f3 --- /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 000000000..b43b5f611 --- /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 000000000..c48d74967 --- /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 000000000..a5e3c4675 --- /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 000000000..823afe2bd --- /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 000000000..ce56dbaa1 --- /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 000000000..3893c8e89 --- /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 000000000..9b9a76109 --- /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 000000000..fa981fbd3 --- /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 000000000..5dca66d80 --- /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 000000000..53f5b3718 --- /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 000000000..0aea44e6a --- /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 000000000..e350a11d3 --- /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 000000000..250e0ce8a --- /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 000000000..a3c8a8700 --- /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 000000000..f59ec9440 --- /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 000000000..2283c30ff --- /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 000000000..21417b599 --- /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 000000000..d0adf2785 --- /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 000000000..6bdf14298 --- /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 000000000..17ee32bb8 --- /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 000000000..2b90451ec --- /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 000000000..839296ca1 --- /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 000000000..743825d60 --- /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 000000000..d4034f10b --- /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 000000000..1374538c2 --- /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 000000000..725d984d8 --- /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 000000000..f24d93c2d --- /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 000000000..d7df52434 --- /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 000000000..bf4da5409 --- /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 000000000..829345d2e --- /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 000000000..ac802ee9e --- /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 000000000..b641ec1da --- /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 000000000..7312509e2 --- /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 000000000..1173a3796 --- /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 000000000..f5c41a232 --- /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 000000000..105f59909 --- /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 000000000..3aaa354f8 --- /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 000000000..6f79442e7 --- /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 000000000..d5074dc91 --- /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 000000000..f02fda353 --- /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 000000000..e0a25a857 --- /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 000000000..7f65eb4ad --- /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 000000000..bee0e8fa5 --- /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 000000000..df437a32c --- /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 000000000..4a49a614f --- /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 000000000..9b20dbfd2 --- /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 000000000..8db0c757e --- /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 000000000..daeee6ba6 --- /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 000000000..9c9f778f0 --- /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 000000000..8c91576f5 --- /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 000000000..26de9ce70 --- /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 000000000..6349bd814 --- /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 000000000..4556cf5c4 --- /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 000000000..ebef9a254 --- /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 000000000..6fb4f5f6e --- /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 000000000..9a3c56ebe --- /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 000000000..9ba67b198 --- /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 000000000..da568a255 --- /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 000000000..c437922e4 --- /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 000000000..81fbd794e --- /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 000000000..eae49c799 --- /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 000000000..c79625d3c --- /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 000000000..a79cb2d76 --- /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 000000000..f8230b21a --- /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 000000000..e79fca70b --- /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 000000000..e0c6ff5e0 --- /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 000000000..0c84352b6 --- /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 000000000..69b9e15f5 --- /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 000000000..81296ba95 --- /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 000000000..cc81c15e4 --- /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 000000000..4c6f3737f --- /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 000000000..e5a4152b5 --- /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 000000000..766a8522e --- /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 000000000..0f36c10ee --- /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 000000000..15d2a972a --- /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 000000000..06cb38606 --- /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 000000000..5cc15c1a8 --- /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 000000000..99ff376d6 --- /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 000000000..0f35077b1 --- /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 000000000..3070314f8 --- /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 000000000..b92fb2229 --- /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 000000000..b08463333 --- /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 000000000..77c18c44b --- /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 000000000..e63a9a57e --- /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 000000000..f1b4bca0a --- /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 000000000..d78d18aba --- /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 000000000..cfee67301 --- /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 000000000..ba819fbce --- /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 000000000..2ae9647e2 --- /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 000000000..73aae5bc9 --- /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 000000000..7f3beb59f --- /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 000000000..24ab54123 --- /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 000000000..7ff669dc9 --- /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 000000000..c6424f141 --- /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 000000000..03573d985 --- /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 000000000..8457b10e1 --- /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 000000000..c05060b7e --- /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 000000000..ad88deca6 --- /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 000000000..0864121de --- /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 000000000..350ea2622 --- /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 000000000..3b80cf973 --- /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 000000000..1d1036c2c --- /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 000000000..585914c80 --- /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 000000000..6bef6f85a --- /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 000000000..0b0224bfc --- /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 000000000..7a8a2c276 --- /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 000000000..99eb1acff --- /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 000000000..a09404fce --- /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 000000000..ab8ad47f9 --- /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 000000000..7492a4281 --- /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 000000000..0a4295114 --- /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 000000000..3269d97c0 --- /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 000000000..8591131be --- /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 000000000..f6c35f7da --- /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 000000000..a1cfcac05 --- /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 000000000..fbaf7b6d9 --- /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 000000000..59d79da9f --- /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 000000000..5368b090e --- /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 000000000..16e4257e1 --- /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 000000000..623f25330 --- /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 000000000..33e270c9e --- /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 000000000..6a1f6dc3d --- /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 000000000..59907b476 --- /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 000000000..1f12ba390 --- /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 000000000..00fcd6f9a --- /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 000000000..1ab8586fc --- /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 000000000..ca1055fd6 --- /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 000000000..5d60a7466 --- /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 000000000..ae497f409 --- /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 000000000..c39bfe064 --- /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 000000000..0be3f80d4 --- /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 000000000..19d11342f --- /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 000000000..5cd0bc177 --- /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 000000000..d74a0f7f4 --- /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 000000000..33d151f82 --- /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 000000000..590294f15 --- /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 000000000..0bbe52248 --- /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 000000000..f167fee5e --- /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 000000000..89f50d0e1 --- /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 000000000..87dc309d8 --- /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 0319ca152..6115f3644 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 ede846cc3..9461cb6bd 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 a3bd78319..d645a3d44 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 f908c0f57..19e4449e6 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 51db0dfbe..7b9f83256 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 661663028..8b9e7df64 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 18c369df4..d3dd0f164 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 727809460..bce974502 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 803e53f08..86561ea7b 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 32aa71799..9e63abcf4 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 3a0905155..5ef105784 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 d5448d0b3..7bbe290ba 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 92a755973..4461bfc65 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 fe310f37a..cd4084c84 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 a3d932b09..a95a675c6 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 d79c6526e..caafaa7ed 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 fada5d291..a5f056493 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 1fec22aec..a2629319b 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 829aab9e4..b47370493 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 11ddaef07..c637c8379 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 acb48fb8a..f69d25b0f 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 15cd110dd..275e8b575 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 8188b7121..80b9d548c 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 eb4ddf0c6..12fe4b3f9 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 000000000..1d21fe75c --- /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 000000000..a66798841 --- /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 ece4e581c..9001c02f4 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 6ab4b181f..9458174ed 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 64e3cc83d..99e239e3b 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -57,7 +57,6 @@ public: 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 @@ private: 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 8558737cf..e57617436 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 dfb88a178..a5be68a7c 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 ca5055ac9..f31c5f979 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 a397000e4..d7fd4b45a 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 f3243296b..0b2a8245d 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 07eca2709..739ba78bf 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 0630fe35f..ac04f96a8 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 9873c717f..02ac2317d 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 c0fe6834a..4398bc29f 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 a077efcf1..ac4ed1b05 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 e664aa781..8de646ae3 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 ab08c0dee..3a51b6626 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 89075e3bb..d0e124f6b 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 957232a8f..1fd8f84f1 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 4725a444e..2848ef3f1 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 3b3e65dbd..ac0fa0f52 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 42b4274ce..a9f5664ec 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 6fee35665..ed8916e63 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 4c1e0feeb..0f723c6c1 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 44d08679f..5e5b79696 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 2457b3b56..ab0d0a1ea 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 1fdc65d43..c64fc93f9 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 178b8c523..46bf80eb7 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 0012af037..ab14e0425 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 9f1bda665..52198a173 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 f0b46072f..c7cc17fc8 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 ab523246e..de92aad7a 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 00c46fcdf..d49ec0709 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 1e6b0828a..9246c162b 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 e936287db..35ba33c6e 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 c541590bd..4207525c7 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 101407783..6aa3ba57d 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 86983b316..ef262b2e6 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 ca8bbba87..0326a5c3a 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 1f4da9eea..58a43c0d2 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 f37bf3d01..17e4d03a2 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 01b301610..a12f171c6 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 d4014c2b0..86f99e298 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 de41539f0..2ea623e7a 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 d84611352..a7fadc434 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 a697c6d25..e5342b2a6 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 830ae064c..8c94644ce 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 13ffc0bac..d90e1fc4b 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 107b2923b..361b0f77b 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 cb88da72b..176d7fd57 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 47b76fa7c..a7c4126ac 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 6371638eb..82dccdab4 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 0315fdab8..af8a08886 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 87450d939..bf74a266c 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 737ff7bf1..a204e6cec 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 af7726df9..f0bf4b7c2 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 16e718d2e..f52551ab4 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 fb2434ec7..a04b87ae6 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 4b4f2cc0c..03879b263 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 57beacaa1..223760723 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 c5c4e44a7..7c6283a8f 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 4a3558b65..b314cd96d 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 6f7390d53..8e48e2b65 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 2b6397269..7bf16956e 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 5412a7952..806a8ebcb 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 d6f7e5d18..b8bf66163 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 7ef55bc3c..e8d034733 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 9d5ce5b84..b92efd885 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 3d350c43b..ef17a9708 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 a0d751938..c7a3d98e1 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 61eae9ff2..d6b9f9d23 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 90dae56f0..ce3c00672 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 be13641c2..7e37d6d4b 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 ee4227b6a..ad1575736 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 295a49504..f5e67f77f 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 e1d0f30fe..d5df28fb0 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 b89c1e0b7..088394ee0 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 c1003538d..0e0a2b9c4 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 77e4303b6..28425b6e1 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 e3a0b7a2f..e01ae0aed 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 561ac2066..6999c39c0 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 c6b246ad0..30f2e5479 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 7a4cfe739..f99c4e447 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 def0a2d31..6b6da1f18 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 b403dc095..d55afc482 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 bfe22582a..4ea58a6ef 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 2ed2b9ad1..676416437 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 0948b51b9..16ee5353f 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 7b197f420..65c93bbb9 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 9c72b82ff..e2cf23756 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 fecb67a65..a78af7dab 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 e400e69ae..5f561185d 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 43629175b..69045f364 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 25ffa4017..5967adc0e 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 9de10889b..490bfd072 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 37649a572..12228009a 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 e95c4144c..49237c2f6 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 d19082f2e..42dc4f015 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 923032af0..337751a72 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 1b2b702fe..1698ac5ac 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 5a116bcc3..48acca95c 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 8c3cd28e3..2b6dba240 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 5b73ed3fe..0456654e3 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 b2a204482..045168cf1 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 07982ca47..461285ae2 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 9d9a139a2..5fcd2c5bf 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 95a0eccb3..ed209e597 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 d8624dc14..2837f7033 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 6296c3778..d69f9d8a5 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 02c4466a2..0e4f1916a 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 0cc4e8f6d..b453446ad 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 144476904..ab41999d5 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 12fa6ec51..30bf46634 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 97661414f..e327d0b33 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 03d2a7aee..5ec8a900a 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 21bf67c89..812cb7e7c 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 7eb5f5285..77f73f112 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 e8e787762..08f7bb9fb 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 cf2b4a615..d6c652e2c 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 809f6ff23..783319395 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 94caf0782..d465600e3 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 36c56834b..6649a86b5 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 f506c41bd..4211b6afe 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 983a3b251..2f655efba 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 efbcf8712..8bf04b987 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 cd74d73ad..bbda84653 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 c7cc887dc..44a8cabb0 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 e7b60d2df..38502d22c 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 2838eb193..5f3d268ca 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 554d080b2..d75ceb831 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 0c92afe38..73b6bfa54 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 83906d675..b8b3ee35d 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 9ad889243..fc75f131f 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 d5e7c0ad4..073db8d4e 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 6d7b03035..65a325d6c 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 d949b2f17..d4e35af33 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 1430fd718..b7bc3e4f9 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 cc819fff8..b43440128 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 fc43fa788..c0fa43e2c 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 cee563173..d153ae724 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 8178c6d03..fbc5befd0 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 cb5303eaf..b81ae9619 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 8d69bcc8d..550c7becb 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 8586396c4..c1c0093ef 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 1d398f833..9ca956c10 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 7e181a097..14d65c4e9 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 7562dfb47..30a2f5e90 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 e5db5ff76..e88877365 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 f8480a327..d66d4efb2 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 2eb72c112..d56a5285e 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 bb73118ec..294cac14a 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 969991871..60492e027 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 c47eebe7b..c5f979bf1 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 3608cab4f..3664a7e26 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 3d48eed79..a70827b93 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 37f40f5e6..4bae497d6 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 95e171475..031507a38 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 6f1ad5458..41c9e4234 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 292284a65..acbe3e456 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 f47026462..bbe782307 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 951a5fbe6..6304c4de5 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 9fa5fd37e..38a00f752 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 c751f4483..331d9cdde 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 c8db1e5aa..0dad89961 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 b3ec1bbe8..259e4aeda 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 fd9d893ae..39c3bb295 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 a088e1681..151b7596c 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 b8c05b72c..4bcfe6f19 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 8e9c2019d..b2162c520 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 f40563602..7bc959ec8 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 2f8a85842..56cac2704 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 46980522d..98c8e3010 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 7d90e0118..21369f10b 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 f9f01a193..143ae35b2 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 4a7837ca2..c1ce89bcf 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 337612d37..10ccc2a37 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 552ce9a82..a22025c4b 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 c45e7a3c7..2897b5151 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 94282bf5c..5678a13fd 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 373416925..c46505c79 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 82632a9e7..375327e65 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 af6fa8283..2c9d979b5 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 4c7fa2692..968ec4767 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 2ea5ea442..0b31d361f 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 df7712b7a..452ceaae6 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 bc7bf5b5a..8c5e4e5df 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 1e9de7755..e8efb735c 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 d75e681a4..73bd6c363 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 339e744d7..9d4e52dc1 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 453f74e33..687491818 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 59dbf172b..1e448c9a4 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 41254b818..0756c1841 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 5038a6fa9..8dd271d9f 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 72ebadd20..0b17b1e4a 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 11de59aba..3133c69ca 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 9f916198c..05fc9447d 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 811f86780..93b424233 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 fceec7ecf..5fe632495 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 13d4997dd..9ebdf0128 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 7ff4c60c3..15ff14a84 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 384a47d89..2f400186a 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 4557c1889..5e6e0305d 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 635da72d6..1076f349a 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 a9cdb84e0..71ed36d97 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 314f2a363..c5cdf8104 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 f8fb81aa8..3b30ac4f7 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 c5ed25e2f..4f1a6f35d 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 4efe81d89..f0ee054b9 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 fa1364297..a0ac5c36d 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 bb350bf8f..6e217ae4f 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 c4a70b03e..78af81f38 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 564ed9664..4421dd3cd 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 6a4e52652..961abd72c 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 4daff379f..7b3360847 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 2e878e437..65c7512d3 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 6710f1fee..cff8bd755 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 95117c38e..b75efc54c 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 f08de996b..7bfbb3401 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 4ad0c872d..2e5380d2c 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 5fb398ad7..1aedecf6a 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 455da2ef5..9193da739 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 f7836b6c6..b007f1855 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 00895bf38..e292340f2 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 276fd4b02..bd66b3a2b 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 4e9e9604f..060fab314 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 89ea5c0ff..05eb4803b 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 6cc82e68a..205626b57 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 27c9e8419..e0d43adbb 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 4f7b27734..3606891ee 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 a9487afa7..77fc5aef0 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 17a8761d9..199fb1f6c 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 7f5dfb2f0..e9ced5f4c 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 f7cfdd7c3..8ce9fba00 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 4fc21bbf5..225e0f627 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 ebe65992a..b4b113e81 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 9bb8261dd..5e5c06553 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 2de873942..da910bace 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 1e06cf8df..efef507dc 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 7fb27c996..01e29b705 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 aed91e002..8c33e4f5d 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 fe7fccfe6..4687422e9 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 d2d0999fa..1b73cecb9 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 ae23c1b8b..1aa05106c 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 67aa196f4..f6f8250ce 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 b90b177b3..a5cb459ad 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 a4154ce63..c2e669b7f 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 b07883c3a..ec9eec6c9 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 a32a54241..a645f1692 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 a4c06ebdc..667abe053 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 75307ad5d..b24ab0170 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 82ea2bf78..a1b58ceb2 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 c7e39cc70..19a85c813 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 7f842bbdd..19e681d6b 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 5f3eeb7ac..2bb86008e 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 86cf1274e..18feab0c1 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 787c1756b..15fe39ccd 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 a489b134b..5fdabc7cb 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 970fec59f..b0527e2b6 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 741efd42b..635e618d5 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 69fb0bef0..1d14937e7 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 b97bb2f4d..a888970e7 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 1ab108f6b..6b20d712c 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 54ad2d843..5bad02dfb 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 9c547d17a..54045ce37 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 dae343217..08b7bc431 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 73228739a..472aa6a33 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 a7280364f..314963368 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 6b15425c9..120b43ce8 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 647de0d24..1b795ad8c 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 3ac614b67..0ee9c551d 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 ab7ba0df1..ee747ae5d 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 14faa2a75..b70f35d2b 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 87104647d..f54b21af8 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 96571f435..5edd71d58 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 6df6e33ef..5b086bab8 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 5b0e70f8c..ce084b1ce 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 7e9518f89..a83f53666 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 3cf202582..5d1e60738 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 eceba8c23..5e88df968 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 444f73265..2a20ca8b6 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 35b6c968f..2fab04a36 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 120c3e07b..7585f848a 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 9fadcbbe9..637a32c02 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 ef68155ad..1caee198a 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 b4546aa55..f0845680f 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 b094f25b7..2b13ba3c3 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 a5e697555..343c672de 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 8e75d82ed..035f66d38 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 f5a29382b..c4f3b3e43 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 85c83bde8..d3c6cb4a6 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 1fd827ed1..12b9ae6b7 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 547ae025b..a39cdedd7 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 7ab2036e1..271bb4864 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 8dc43d721..8d38dcc16 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 f0b29f301..94de51b88 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 520c87b92..39a7f91b3 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 4dd86f958..59731d617 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 e664291f5..0a1e38fa6 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 e0aa0a385..442d64654 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 95733af88..c3f6ea6a2 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 074100d89..7fc927a4a 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 cc009509f..6221f1160 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 e39b66b44..272160003 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 5a98c4c4d..ed80715e9 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 f01514cc5..a5d8198b0 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 ae04949d9..1b9b3a84a 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 9f57a4739..b00d50f26 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 6d388c19e..cc8d23398 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 0d42afa97..92aacb229 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 ec79843b1..fb73227b7 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 8fdd1f002..4255445b3 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 1b59fd598..4cffa6a02 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 0fb885604..dc1d78c74 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 fe3cf5812..ef6e12ab6 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 c10f9ddf2..7af26af63 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 e0452c4b8..e7c28202c 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 0eeb248a6..071c3c463 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 c95cf5454..3d4d65f0a 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 35d4f0332..04a797e20 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 076131cde..bb5f02980 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 7e60a54be..c8b22424c 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 b4ad9ed8e..e2f554dd0 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 d59bd5644..4aac31ddb 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 e4787540d..43b9ade6a 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 0617c47e4..2e818561c 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 73aee8516..4815349d7 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 b6eb0b6cf..a0821ab37 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 e747e8503..92a0ba825 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 8265f500e..63c4f8561 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 15e56f4d6..e2f130507 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 0e777a5a5..e2516b45b 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 aacad246a..e6e0553c1 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 fbb149c68..da8d797b8 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 1c246a754..6053bd9ac 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 28520d3c5..104dc2822 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 105970c3c..85e86e005 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 6770fee2b..75a045d05 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 18d404df0..1c79777d2 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 48b9d39cf..1985f6c08 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 03dab25f9..be2cfe9d7 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 76a459160..81f82451f 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 6901f9f17..e1e1c13ba 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 fcf1a4478..284bdbf3d 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 217a043ad..ac7e426ab 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 cec419633..77ac89a60 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 b6e120f40..d41c18b04 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 4f1c44123..ff4a0eb1d 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 ea849ead9..06847711e 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 a48de0002..e075f06a2 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 7d2d7bc33..32d74f180 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 f42de9976..b41998c59 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 d23d07d82..b52ec0c05 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 32d6b339b..8604be0e3 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 775df55f4..3cf38ef38 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 f9d48a227..4b1aa1643 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 685c42a24..596f56cb0 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 7d61b1031..b87b5dbbc 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 c23bc6ee8..cbd0cdb25 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 6c0ceef63..4ff056157 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 e74e788aa..f237ea8bb 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 39c46fb96..b5f3dd872 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 f285d6b5e..279c0d901 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 f180d50ad..94da17faa 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 0d352a3f9..edca6b642 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 ab08b18e8..3b7a39181 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 836b4371c..bbed85bb0 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 7d493efbc..bf1046fb2 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 4595fe899..bee5381c8 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 6783b6eee..44b2ecc61 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 b80d4ea99..faa0304df 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 5e985d78e..9238cb057 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 584bbb73d..9036db709 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 0dea12292..5eeae71ba 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 8629be3f6..f8cc0558a 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 80758f082..cceace3bb 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 1c1397061..32e96b9f3 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 2dd207fbf..bc05f09f8 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 c6b93a648..6ad93184a 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 0d49d713b..09d366fb2 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 ae6beaa75..05ad7b743 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 77e9306c9..47e114373 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 01e573199..86f175d69 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 76bd6a510..f727b0e93 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 b4f6a5a7e..aa8ae0ad4 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 67d692f70..f54087a7d 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 8d40256eb..7bfc4d788 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 089098215..66d16db1e 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 9adf68be5..a2ac495a0 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 b3a05d38f..9de594351 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 054d0b53c..8d306ca16 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 f9510e32f..9a169b435 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 4911a6bd2..4968e2b04 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 fac0eaa06..f8c37f2c5 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 62d21dd0f..2b7d1048f 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 912246bea..069c68cab 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 694d21847..b6ee0377f 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 629b5451e..ea4ca9ea2 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 6f1d1817c..1608dd6fb 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 7dabb4d47..c7d86ef98 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 acf71b1d9..2d7dbeb4a 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 4104c9567..cd32d8530 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 d96a7b0be..100e5ccc6 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 e1132ad8b..d197d4ff3 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 fadfbd61f..10f8814a6 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 d633e9500..3aef8c99c 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 c1a99ef34..5ac0bfc00 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 5bfef91b1..b799760f8 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 016dd9bb8..803b28970 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 22cb7631e..d40e2283f 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 12759e230..a9612a392 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 617eebb64..403c57962 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 20f81d614..d1f45a623 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 2a42adefe..a02243a25 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 8b2afc780..f952e40bd 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 b4e7e3972..0add6947b 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -57,8 +57,8 @@ public: /// 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 2b7e201af..0f49a6401 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 055b355b7..5ab226826 100644 --- a/test/TestCaseReader.h +++ b/test/TestCaseReader.h @@ -40,11 +40,9 @@ public: 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 8b5112e12..ded01f8dd 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 d8defa17a..6340c71c3 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 9164bf06c..d93e18d06 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 887faf9e4..58c37ebd6 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 2d9d71d7c..98e4d1081 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 da85c9ed0..ad689ffcf 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 | 99 +++++++++++++++-------- 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, 72 insertions(+), 36 deletions(-) diff --git a/test/tools/afl_fuzzer.cpp b/test/tools/afl_fuzzer.cpp index 1ca5428e1..eff4bc55a 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 f66c2e841..e4de0f185 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; +using namespace solidity::langutil; -static vector s_evmVersions = { - "homestead", - "tangerineWhistle", - "spuriousDragon", - "byzantium", - "constantinople", - "petersburg", - "istanbul" +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 edf196c1c..801c8c1c1 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 3a2ac5f27..efed3769f 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 72a59cba4..fc431ffe5 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 21a105db5..1d40c35b1 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 000000000..ff9c03cbe --- /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 000000000..bfc8b2013 --- /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 000000000..a2b3de54f --- /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 000000000..c3ff22ca3 --- /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 e802c4204..ee0a39163 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 f9953c17b..edd5de4d2 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 6bdb48fba..78b2ab310 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 9c2d9a384..2472d9467 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 d760e0810..9ed35e694 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 5aada86c3..73943b18a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -701,7 +701,9 @@ public: /// 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 0aa3d2984..501184c9c 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 f0892b83b..1fd96ff76 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 000000000..f6fa4d45e --- /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 000000000..404013ee6 --- /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 000000000..d02284aef --- /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 000000000..4e6e02598 --- /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 c397cd1f4..7dcfddd79 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 6da9751b9..df44f2ba4 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -98,6 +98,10 @@ private: 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 5d4e012f3..e69f0fc5c 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 7dcfddd79..a457750d2 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 df44f2ba4..10fed6de2 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -94,10 +94,6 @@ private: 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 aab34db61..04dfbe3dc 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 da0296eff..b29938f22 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 2e72c31f6..9814c9111 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -169,6 +169,7 @@ public: 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 6115f3644..ac1dda7dd 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 000000000..8721f47a4 --- /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 000000000..97cbe4ab4 --- /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 000000000..7197a4edb --- /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 7ed44d236..e67ccb8f5 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 a76538375..e9e3630a8 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -54,6 +54,8 @@ public: 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 @@ public: /// 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 @@ protected: 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 c238a3a3c..610c6f5dd 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 e506a9fdb..fc8c63c67 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 @@ public: 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 @@ private: /// 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 7e447a9a1..5f1ca736c 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 e7a1e9667..ccf5588bb 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 4ea9a01ae..76eeb5956 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 9ed35e694..76eeb4fce 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 73943b18a..d0e774cb7 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -895,6 +895,8 @@ public: /// @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 cb195c49f..26cff59ec 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 8c5775239..ec846af83 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -64,6 +64,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: 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 c559c0b7c..d4f35ad79 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 6fffbd5b5..d5f5ffe33 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 0a2ecf7e8..0916da281 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -99,6 +99,7 @@ private: 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 d4f3d460d..c71d067c4 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 5fd17bf5c..4b1c80ede 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 1cd4def01..cd72f37e0 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ public: 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 @@ public: 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 @@ public: 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 7c0eca276..e64420bd9 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 4d93f4e76..782b687fc 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 000000000..f671065ac --- /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 000000000..4a037cadc --- /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 000000000..ee9ed0678 --- /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 2d7057f7c..a402101c4 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 f671065ac..c815a18c3 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 000000000..f61009f60 --- /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 000000000..0673aafb5 --- /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 000000000..b9e362dbd --- /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 4a037cadc..000000000 --- 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 ee9ed0678..387541066 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 000000000..d83da476d --- /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 181a0fbcf..d63d9aec5 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 000000000..598e7a16f --- /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 fd5f92bbe..241a80f46 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 000000000..bd3b05114 --- /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 000000000..433ba99c5 --- /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 | 27 ++++++++--- tools/yulPhaser/Phaser.cpp | 2 + 4 files changed, 105 insertions(+), 28 deletions(-) diff --git a/test/yulPhaser/FitnessMetrics.cpp b/test/yulPhaser/FitnessMetrics.cpp index 8b62b03b7..524ef6357 100644 --- a/test/yulPhaser/FitnessMetrics.cpp +++ b/test/yulPhaser/FitnessMetrics.cpp @@ -76,15 +76,16 @@ protected: 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 49482d0af..5279cea72 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 { - Program programCopy = m_program; + 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 = 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 e79d99ff4..72e811152 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 @@ public: * 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) {} + m_programCache(std::move(_programCache)), + m_repetitionCount(_repetitionCount) + { + assert(m_program.has_value() == (m_programCache == nullptr)); + } - Program const& program() const { return m_program; } + 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 b29938f22..cfe5cbd1f 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 0b54ad38f..0382cc90d 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 b9f22171b..e7ea5a072 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 ff0d0e3c3..8ee97ac48 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -50,10 +51,12 @@ public: 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 @@ public: 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 @@ private: ); 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 cfe5cbd1f..80aed0226 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 04dfbe3dc..ca45c0771 100644 --- a/test/yulPhaser/Phaser.cpp +++ b/test/yulPhaser/Phaser.cpp @@ -55,7 +55,7 @@ protected: }; }; -class FitnessMetricFactoryFixture +class FixtureWithPrograms { protected: vector m_sourceStreams = { @@ -68,6 +68,11 @@ protected: 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 80aed0226..054b6e99e 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 9814c9111..256d9a288 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 @@ public: ); }; +/** + * 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 ca45c0771..633462865 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 054b6e99e..218b358a0 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 256d9a288..ba816044c 100644 --- a/tools/yulPhaser/Phaser.h +++ b/tools/yulPhaser/Phaser.h @@ -120,7 +120,8 @@ public: 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 2472d9467..96f3a1444 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 8ea07f182..94a16d6f1 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 000000000..50f0eb365 --- /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 000000000..709a40e26 --- /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 0382cc90d..ce6f43bd2 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 @@ public: 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 - ); + AlgorithmRunner runner(population, {}, m_options, m_output); + RandomisingAlgorithm algorithm; - CountingAlgorithm 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)))); - 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); - 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 ce6f43bd2..80a431fdc 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -90,6 +90,7 @@ protected: } 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 @@ public: 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 80a431fdc..8cd4ec803 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 e7ea5a072..dd1275daf 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 8ee97ac48..978c6a7cb 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -47,6 +47,7 @@ public: bool randomiseDuplicates = false; std::optional minChromosomeLength = std::nullopt; std::optional maxChromosomeLength = std::nullopt; + bool showInitialPopulation = false; }; AlgorithmRunner( @@ -66,6 +67,7 @@ public: 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 218b358a0..50cad1659 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 | 29 +++++++- tools/yulPhaser/AlgorithmRunner.h | 6 ++ tools/yulPhaser/Phaser.cpp | 12 ++++ 4 files changed, 144 insertions(+), 3 deletions(-) diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 8cd4ec803..b3379d661 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -78,6 +78,12 @@ protected: 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 dd1275daf..90440e120 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -41,13 +41,36 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) m_population = _algorithm.runNextRound(m_population); randomiseDuplicates(); - m_outputStream << "---------- ROUND " << round + 1 << " ----------" << endl; - m_outputStream << m_population; - + 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 << " | "; + + m_outputStream << m_population.individuals()[0] << endl; + } +} + void AlgorithmRunner::printInitialPopulation() const { if (!m_options.showInitialPopulation) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 978c6a7cb..abef48869 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -48,6 +49,8 @@ public: std::optional minChromosomeLength = std::nullopt; std::optional maxChromosomeLength = std::nullopt; bool showInitialPopulation = false; + bool showOnlyTopChromosome = false; + bool showRoundInfo = true; }; AlgorithmRunner( @@ -67,6 +70,9 @@ public: 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 50cad1659..344b93208 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 b3379d661..831cb360a 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 90440e120..9ddce41bc 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 abef48869..7c6946391 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -71,7 +71,9 @@ public: 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 344b93208..2a4ee4b86 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 ba816044c..ef7c00f41 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 @@ private: 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 2a4ee4b86..0bfd6a433 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 ef7c00f41..77e9e48c8 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 @@ private: 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 598e7a16f..1ed6024bc 100644 --- a/test/yulPhaser/ProgramCache.cpp +++ b/test/yulPhaser/ProgramCache.cpp @@ -71,6 +71,15 @@ protected: 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 bd3b05114..7acec16bd 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 433ba99c5..8cc830098 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 @@ public: 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 @@ private: 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 831cb360a..fa87579dd 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 9ddce41bc..5e03e2820 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 7c6946391..d1cffb30a 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -51,6 +51,7 @@ public: bool showInitialPopulation = false; bool showOnlyTopChromosome = false; bool showRoundInfo = true; + bool showCacheStats = false; }; AlgorithmRunner( @@ -76,6 +77,7 @@ private: 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 0bfd6a433..6e6ec7a3f 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 5e03e2820..d3bda6960 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 d1cffb30a..4326ce227 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 @@ public: 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 fa87579dd..9d062d0ac 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -84,7 +84,7 @@ protected: 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 d3bda6960..c402e5d84 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 9d062d0ac..8dd6e7564 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -76,8 +76,7 @@ protected: 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 87df4e59b..169cbfe30 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 6e6ec7a3f..2e38edbf0 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 87df4e59b..71b32da70 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 2472d9467..031fe5a67 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 e91f6446c..90c2931c5 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 417501907..f6972cf04 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -74,6 +74,7 @@ private: 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 4a674c99e..dba182345 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 c0a98aefa..c3636ff06 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 000000000..dd39453e8 --- /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 bb54c836f..ba2651e94 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 1e851937c..e10c16d39 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 ff193d2e2..1f7b7a5e0 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 512be65bb..106ada820 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 000000000..195048e56 --- /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 000000000..d26644462 --- /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 a2475b337..1d9655a9c 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 | 1268 ----------------- .../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, 1295 insertions(+), 1268 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 ae39bec0e..69e645494 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,92 +4076,6 @@ 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) -{ - 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_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"( @@ -4630,26 +4102,6 @@ BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds) ); } -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 { @@ -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 000000000..6b6e55e02 --- /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 000000000..9ae6602f3 --- /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 000000000..af37480a3 --- /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 000000000..6ca284908 --- /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 000000000..9cec148c7 --- /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 000000000..d21bcc53f --- /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 000000000..2fc479d0e --- /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 000000000..c6ada8c6a --- /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 000000000..6cacbe300 --- /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 000000000..bbc5ddaa4 --- /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 000000000..20f594764 --- /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 000000000..a8fd89833 --- /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 000000000..5b7fd7ac3 --- /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 000000000..c2c2fa70a --- /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 000000000..04b2ed15d --- /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 000000000..ae7d1e2ef --- /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 000000000..dbf6e4440 --- /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 000000000..c94cfc776 --- /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 000000000..beff156f7 --- /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 000000000..32b90748e --- /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 000000000..5adc97378 --- /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 000000000..ffa22b8a2 --- /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 000000000..498449d17 --- /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 000000000..b65a3d254 --- /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 000000000..9ab74eaf3 --- /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 000000000..2e771032b --- /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 000000000..91a26945c --- /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 000000000..972aee839 --- /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 000000000..01397f55f --- /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 000000000..b157178fb --- /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 000000000..be824b759 --- /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 000000000..7a8a18670 --- /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 000000000..c16705643 --- /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 000000000..11b9a5339 --- /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 000000000..646f8f6e9 --- /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 000000000..07f6c038d --- /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 000000000..b2876eeb3 --- /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 000000000..c0d6be8bd --- /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 000000000..df0570cb7 --- /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 000000000..0c1949a59 --- /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 000000000..54ac9540f --- /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 000000000..c59107f52 --- /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 000000000..6e462e704 --- /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 000000000..74e9d53b0 --- /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 000000000..2466298f0 --- /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 000000000..06dcf8eb5 --- /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 000000000..643bc5e62 --- /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 000000000..96c5419be --- /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 000000000..a193e8752 --- /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 000000000..9c2ec2e53 --- /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 000000000..9578fc4f7 --- /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 000000000..a6ec607f4 --- /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 000000000..dbd67ab58 --- /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 | 95 +++++++------------ 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, 157 insertions(+), 115 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index a76e6e274..b711758d6 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 052970bc8..4bbacbdf3 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -689,6 +689,18 @@ public: 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 @@ public: 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 @@ public: ModifierDefinitionAnnotation& annotation() const override; + ModifierDefinition const& resolveVirtual( + ContractDefinition const& _mostDerivedContract, + ContractDefinition const* _searchStart = nullptr + ) const override; + + private: ASTPointer m_body; }; @@ -1010,6 +1034,14 @@ public: 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 26cff59ec..6984a030b 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -272,57 +272,43 @@ 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; } +ContractDefinition const& CompilerContext::mostDerivedContract() const +{ + solAssert(m_mostDerivedContract, "Most derived contract not set."); + return *m_mostDerivedContract; +} + Declaration const* CompilerContext::nextFunctionToCompile() const { return m_functionCompilationQueue.nextFunctionToCompile(); } -ModifierDefinition const& CompilerContext::resolveVirtualFunctionModifier( - ModifierDefinition const& _modifier -) 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."); -} - unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declaration) const { auto res = m_localVariables.find(&_declaration); @@ -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 ec846af83..a8e494435 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -114,15 +114,14 @@ public: /// @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 @@ public: /// 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 @@ public: 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 @@ private: /// 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 d5f5ffe33..50fb030d2 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 c71d067c4..58992426b 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 7184247f4..288da5937 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 473b62482..b0fc92cdb 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -61,11 +61,12 @@ public: 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 @@ public: 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 @@ private: 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 9c7d9c8ac..4ca00befb 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 1d40c35b1..b5d9589c0 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 cb0066bee..cdaee104b 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 151474171..40d51498b 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 4ca00befb..2aff9c3f8 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(); - // TODO base constructors + Whiskers t(R"X( + let programSize := datasize("") + let argSize := sub(codesize(), programSize) - out << m_context.functionName(*constructor) + "()\n"; + let memoryDataOffset := (argSize) + codecopy(memoryDataOffset, programSize, argSize) + + (memoryDataOffset, add(memoryDataOffset, argSize)) + + () + )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 << 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 000000000..19f0bdb57 --- /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 b8b2893a2..000000000 --- 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 085bf99e7..b4082fced 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 96f3a1444..f269e049f 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 1345fbf90..784701d22 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 000000000..d9737a807 --- /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 000000000..2fa48cfb1 --- /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 000000000..2a5d62752 --- /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 ac1dda7dd..9ccf7a663 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 4461bfc65..f2034272a 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 12fe4b3f9..8d647a4a7 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 a66798841..c56bdc6c9 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 4d132d684..b512f9eb2 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 784701d22..8067580c8 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 ecda3e994..625502f25 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 000000000..2fc49b1db --- /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 33511f020..7a0a7380a 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). +Immutable +========= -Not all types for constants are implemented at this time. The only supported types are -value types and strings. +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 b4082fced..3c30fec86 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 275e8b575..1566a8859 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 b5d9589c0..8a98e8d36 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 b512f9eb2..f20b05aa5 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 58992426b..fed3751fa 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 000000000..c42f84862 --- /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 9ccf7a663..23da90b8f 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 388bd4b56..066e17e93 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 d8daf565e..0d0f30c48 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 5a76a3f18..fd7bca132 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 1103db5a8..2b596f4ed 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 50fb030d2..49b08b6da 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 fed3751fa..a406cdeb8 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 4b1c80ede..3a04d6f92 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 000000000..3f71a31e0 --- /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 1345fbf90..4f4cbe379 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 f3be90715..4966b4e85 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 edae7549d..c43dbad6d 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 a0b6f71e7..68e3b2c44 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 4c1f96e6e..9035caa25 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 000000000..ddb5faa9f --- /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 000000000..19a58b234 --- /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 000000000..1d4302755 --- /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 000000000..180feb770 --- /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 000000000..bba9daf34 --- /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 000000000..c3f240915 --- /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 000000000..72884e741 --- /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 000000000..d72310924 --- /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 000000000..25654b1dd --- /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 000000000..40ddc3777 --- /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 000000000..e93d9798f --- /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 000000000..b3e9f46d1 --- /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 000000000..7da6bef92 --- /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 000000000..5d3a6d5bd --- /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 000000000..6df4939cf --- /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 000000000..5cb580528 --- /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 000000000..a6dd300ce --- /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 000000000..e8ad5e485 --- /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 000000000..f820456e1 --- /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 000000000..3b4552f86 --- /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 000000000..1dd8d2f57 --- /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 000000000..ca43dc346 --- /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 000000000..6834525d5 --- /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 000000000..e2e274196 --- /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 000000000..cd6fee8db --- /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 000000000..20e72e5db --- /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 000000000..2c47731aa --- /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 000000000..a510bd40d --- /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 4bbacbdf3..3d64c828f 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1039,7 +1039,7 @@ public: 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 f20b05aa5..6ca68ea85 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 ba2651e94..c7a517a0b 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 000000000..e80902009 --- /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 000000000..5845ba011 --- /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 e6a2408f1..8e7bef338 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 d428a6ac9..a26ab81bd 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -158,7 +158,7 @@ private: /// 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 3d64c828f..4979d5d4e 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 86636684c..a724472d0 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 781f68d6b..fe0268fb1 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 000000000..702f03079 --- /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 000000000..b8557321b --- /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 000000000..1423659c8 --- /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 000000000..ad17635c4 --- /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 000000000..0b2207808 --- /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 000000000..f3b724f03 --- /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 000000000..2c1c37c79 --- /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 000000000..b26666530 --- /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 000000000..a9a1b3a22 --- /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 000000000..54ac9f615 --- /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 000000000..def28fad2 --- /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 000000000..c836beb27 --- /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 000000000..2a4365e69 --- /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 000000000..04eaa621d --- /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 000000000..2ec62e931 --- /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 7740f8643..000000000 --- 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 b4960f25b..3d8e04636 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 000000000..0068bf87d --- /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 000000000..5f659bff6 --- /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 000000000..ee794fd37 --- /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 000000000..0d98f8b40 --- /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 000000000..16ed52f36 --- /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 000000000..ed352746f --- /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 000000000..d56fb487a --- /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 000000000..5dda6bfb0 --- /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 000000000..278efe55f --- /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 000000000..f1e60dbd8 --- /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 000000000..24a5239ed --- /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 000000000..a6db6a665 --- /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 000000000..2827ab389 --- /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 000000000..c71335b83 --- /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 000000000..eaabbb71a --- /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 000000000..8ff940fef --- /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 000000000..2cfc22a85 --- /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 000000000..b64f236a9 --- /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 000000000..4de778ba3 --- /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 000000000..d35c68d8a --- /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 000000000..0fd5461d4 --- /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 000000000..4b880c8e8 --- /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 000000000..c84f72408 --- /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 000000000..a8b91a639 --- /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 000000000..18c60ea9d --- /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 000000000..69aa5448f --- /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 000000000..2b5614650 --- /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 000000000..e844de080 --- /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 000000000..592633379 --- /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 1c0e7a46f..9028c7ccc 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 f20b05aa5..05b3fa8c1 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 cc4489e9f..b36af7e3f 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 76eeb4fce..3fc649caf 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 ba664dbb6..28a4f69fb 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 8841e98ad..b902f9f64 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 @@ public: /// 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 @@ public: /// 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 @@ public: 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 288da5937..26f6f0309 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 2aff9c3f8..5ae4b71d7 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 d1ec580f6..e0c1dcd4f 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -61,6 +61,9 @@ private: /// 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 8a98e8d36..57c8cb152 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 39dbb67d7..710961cd7 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -46,6 +46,8 @@ public: /// 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 @@ private: 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 82e974025..cb89a6911 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 fc88acf50..24a2a10aa 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 428c7911e..8028e5dd6 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 4a348343b..a9588d145 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 4302701bd..552712154 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 0b92fceea..48c1146fa 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 000000000..5344ae67f --- /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 000000000..aa1349cb8 --- /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 000000000..1f490ba59 --- /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 000000000..31dd0a66a --- /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 000000000..6cf73bd8e --- /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 000000000..1f9e70db7 --- /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 000000000..5bd433a3d --- /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 000000000..d0085dec1 --- /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 74fa8d458..ba973bffa 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 000000000..b94334d38 --- /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 82a40eced..2c757e402 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 e80902009..6e0d0f6c7 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 49b08b6da..822ce3b66 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 a406cdeb8..a02497561 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 000000000..851120847 --- /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 000000000..bb4b191cf --- /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 000000000..e4aa474f2 --- /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 a724472d0..021a742f5 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 8e7bef338..2bdc706a2 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 851120847..000000000 --- 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 c815a18c3..000000000 --- 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 000000000..7ab8393cf --- /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 90dad003a..db67dc392 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 @@ protected: 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 1566a8859..09e863394 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 09e863394..f7aca7190 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 8f285c883..549fc05e9 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 be75931f2..e1c28a8b5 100644 --- a/libsolidity/formal/SymbolicVariables.h +++ b/libsolidity/formal/SymbolicVariables.h @@ -47,6 +47,8 @@ public: EncodingContext& _context ); + SymbolicVariable(SymbolicVariable&&) = default; + virtual ~SymbolicVariable() = default; virtual Expression currentValue(frontend::TypePointer const& _targetType = TypePointer{}) const; @@ -212,6 +214,13 @@ public: 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 e67ccb8f5..fa6ea4f16 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 ccf5588bb..ab0e26507 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 6984a030b..06080afbd 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 77e00df05..00662718e 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 000000000..15213be74 --- /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 000000000..1ba91eff7 --- /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 2c757e402..17d4fd0ae 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 00662718e..a97114e83 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 1ba91eff7..2788a8e73 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 8d647a4a7..02218592e 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 0d0f30c48..b12393016 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