Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2020-03-24 13:35:41 +01:00
856 changed files with 12967 additions and 8148 deletions
+14 -2
View File
@@ -13,6 +13,8 @@ set(sources
Metadata.h
TestCase.cpp
TestCase.h
TestCaseReader.cpp
TestCaseReader.h
)
detect_stray_source_files("${sources}" ".")
@@ -139,12 +141,17 @@ set(libyul_sources
detect_stray_source_files("${libyul_sources}" "libyul/")
set(yul_phaser_sources
yulPhaser/Common.h
yulPhaser/TestHelpers.h
yulPhaser/TestHelpers.cpp
yulPhaser/TestHelpersTest.cpp
yulPhaser/Common.cpp
yulPhaser/CommonTest.cpp
yulPhaser/Chromosome.cpp
yulPhaser/FitnessMetrics.cpp
yulPhaser/AlgorithmRunner.cpp
yulPhaser/GeneticAlgorithms.cpp
yulPhaser/Mutations.cpp
yulPhaser/PairSelections.cpp
yulPhaser/Phaser.cpp
yulPhaser/Population.cpp
yulPhaser/Program.cpp
yulPhaser/Selections.cpp
@@ -153,9 +160,14 @@ 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/Common.cpp
../tools/yulPhaser/Chromosome.cpp
../tools/yulPhaser/FitnessMetrics.cpp
../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
+2 -1
View File
@@ -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
+1
View File
@@ -50,6 +50,7 @@ struct CommonOptions: boost::noncopyable
bool disableSMT = false;
bool useABIEncoderV2 = false;
bool showMessages = false;
bool showMetadata = false;
langutil::EVMVersion evmVersion() const;
+21 -21
View File
@@ -56,37 +56,37 @@ 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)
{
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
+2 -1
View File
@@ -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<SyntaxTestError> parseExpectations(std::istream& _stream);
+9 -118
View File
@@ -18,16 +18,9 @@
#include <test/Common.h>
#include <test/TestCase.h>
#include <libsolutil/StringUtils.h>
#include <boost/algorithm/cxx11/none_of.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/range/adaptor/map.hpp>
#include <stdexcept>
#include <iostream>
using namespace std;
@@ -35,13 +28,14 @@ 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)
{
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<map<string, string>, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream)
{
map<string, string> 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<string, string> TestCase::parseSourcesAndSettings(istream& _stream)
{
return get<0>(parseSourcesAndSettingsWithLineNumbers(_stream));
}
pair<string, size_t> 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,18 +60,11 @@ 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"))
return;
string versionString = m_settings["EVMVersion"];
m_validatedSettings["EVMVersion"] = versionString;
m_settings.erase("EVMVersion");
TestCase::validateSettings();
if (versionString.empty())
string versionString = m_reader.stringSetting("EVMVersion", "any");
if (versionString == "any")
return;
string comparator;
+13 -24
View File
@@ -17,16 +17,13 @@
#pragma once
#include <test/TestCaseReader.h>
#include <liblangutil/EVMVersion.h>
#include <boost/filesystem.hpp>
#include <functional>
#include <iosfwd>
#include <memory>
#include <string>
#include <vector>
#include <map>
namespace solidity::frontend::test
{
@@ -60,31 +57,27 @@ 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;
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::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumbers(std::istream& _file);
std::map<std::string, std::string> parseSourcesAndSettings(std::istream& _file);
std::pair<std::string, std::size_t> 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<typename IteratorType>
static void skipWhitespace(IteratorType& _it, IteratorType _end)
@@ -100,18 +93,14 @@ protected:
++_it;
}
/// Parsed settings.
std::map<std::string, std::string> m_settings;
/// Updated settings after validation.
std::map<std::string, std::string> m_validatedSettings;
TestCaseReader m_reader;
bool m_shouldRun = true;
};
class EVMVersionRestrictedTestCase: public TestCase
{
public:
void validateSettings() override;
protected:
EVMVersionRestrictedTestCase(std::string const& _filename);
};
}
+164
View File
@@ -0,0 +1,164 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <test/TestCaseReader.h>
#include <libsolutil/StringUtils.h>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/throw_exception.hpp>
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::boolSetting(std::string const& _name, bool _defaultValue)
{
if (m_settings.count(_name) == 0)
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 (m_settings.count(_name) == 0)
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 (m_settings.count(_name) == 0)
return _defaultValue;
m_unreadSettings.erase(_name);
return m_settings.at(_name);
}
void TestCaseReader::ensureAllSettingsRead() const
{
if (!m_unreadSettings.empty())
throw runtime_error(
"Unknown setting(s): " +
util::joinHumanReadable(m_unreadSettings | boost::adaptors::map_keys)
);
}
pair<map<string, string>, size_t> TestCaseReader::parseSourcesAndSettingsWithLineNumber(istream& _stream)
{
map<string, string> 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;
}
+59
View File
@@ -0,0 +1,59 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <map>
#include <string>
#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<std::string, std::string> const& sources() { return m_sources; }
std::string const& source();
std::size_t lineNumber() { return m_lineNumber; }
std::map<std::string, std::string> const& settings() { return m_settings; }
std::ifstream& stream() { return m_file; }
std::string simpleExpectations();
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 ensureAllSettingsRead() const;
private:
std::pair<std::map<std::string, std::string>, std::size_t> parseSourcesAndSettingsWithLineNumber(std::istream& _file);
static std::string parseSimpleExpectations(std::istream& _file);
std::ifstream m_file;
std::map<std::string, std::string> m_sources;
std::size_t m_lineNumber = 0;
std::map<std::string, std::string> m_settings;
std::map<std::string, std::string> m_unreadSettings; ///< tracks which settings are left unread
};
}
-1
View File
@@ -94,7 +94,6 @@ int registerTests(
{
stringstream errorStream;
auto testCase = _testCaseCreator(config);
testCase->validateSettings();
if (testCase->shouldRun())
switch (testCase->run(errorStream))
{
+2 -53
View File
@@ -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 ]
+4 -8
View File
@@ -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)
@@ -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":
+7 -28
View File
@@ -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)
+1 -1
View File
@@ -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<string> SMTCheckerJSONTest::hashesFromJson(Json::Value const& _jsonObj, string const& _auxInput, string const& _smtlib)
+11 -16
View File
@@ -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)
@@ -62,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);
}
+25 -42
View File
@@ -37,59 +37,42 @@ 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"))
string choice = m_reader.stringSetting("compileViaYul", "false");
if (choice == "also")
{
if (m_settings["compileViaYul"] == "also")
{
m_validatedSettings["compileViaYul"] = m_settings["compileViaYul"];
m_runWithYul = true;
m_runWithoutYul = true;
}
else
{
m_validatedSettings["compileViaYul"] = "only";
m_runWithYul = true;
m_runWithoutYul = false;
}
m_settings.erase("compileViaYul");
m_runWithYul = true;
m_runWithoutYul = true;
}
if (m_settings.count("ABIEncoderV1Only"))
else if (choice == "true")
{
if (m_settings["ABIEncoderV1Only"] == "true")
{
m_validatedSettings["ABIEncoderV1Only"] = "true";
m_runWithABIEncoderV1Only = true;
}
m_settings.erase("ABIEncoderV1Only");
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)
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 +135,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"
);
+1
View File
@@ -65,6 +65,7 @@ private:
bool m_runWithYul = false;
bool m_runWithoutYul = true;
bool m_runWithABIEncoderV1Only = false;
bool m_allowNonExistingFunctions = false;
};
}
File diff suppressed because it is too large Load Diff
@@ -21,6 +21,7 @@
*/
#include <cstdlib>
#include <iostream>
#include <boost/test/framework.hpp>
#include <test/libsolidity/SolidityExecutionFramework.h>
@@ -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;
}
@@ -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;
};
+2 -15
View File
@@ -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;
}
@@ -60,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()
+3 -3
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"
@@ -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
@@ -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"
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
contract Lotto {
uint256 public constant ticketPrice = 555;
}
// ----
// ticketPrice() -> 555
@@ -0,0 +1,8 @@
contract Lotto {
uint256 public ticketPrice = 500;
}
// ====
// compileViaYul: also
// ----
// ticketPrice() -> 500
@@ -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
@@ -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
@@ -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 #
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,11 @@
contract c {
uint256[] data;
function test() public returns (bool) {
data.pop();
return true;
}
}
// ----
// test() -> FAILURE
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ->
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
contract C {
function f() public returns (uint256) {
uint256[][] memory a = new uint256[][](0);
return 7;
}
}
// ----
// f() -> 7
@@ -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"
@@ -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
@@ -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 #
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,8 @@
contract C {
function f() public returns (uint256) {
return ([1, 2, 3, 4][2]);
}
}
// ----
// f() -> 3
@@ -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"
@@ -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
@@ -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
@@ -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
@@ -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"
@@ -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"
@@ -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
@@ -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
@@ -0,0 +1,10 @@
contract C {
function f() public returns (bytes32) {
return keccak256("");
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
@@ -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

Some files were not shown because too many files have changed in this diff Show More