Merge pull request #7278 from ethereum/develop

Merge develop into develop_060
This commit is contained in:
Mathias L. Baumann 2019-08-26 10:26:48 +02:00 committed by GitHub
commit 502bf01be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 985 additions and 493 deletions

View File

@ -47,7 +47,7 @@ usual ``//`` and ``/* */`` comments. There is one exception: Identifiers in inli
these curly braces, you can use the following (see the later sections for more details): these curly braces, you can use the following (see the later sections for more details):
- literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters) - literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters)
- opcodes in functional style, e.g. ``add(1, mlod(0))`` - opcodes in functional style, e.g. ``add(1, mload(0))``
- variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned) - variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
- identifiers (assembly-local variables and externals if used as inline assembly), e.g. ``add(3, x)``, ``sstore(x_slot, 2)`` - identifiers (assembly-local variables and externals if used as inline assembly), e.g. ``add(3, x)``, ``sstore(x_slot, 2)``
- assignments, e.g. ``x := add(y, 3)`` - assignments, e.g. ``x := add(y, 3)``

View File

@ -124,7 +124,7 @@ Encoding of the Metadata Hash in the Bytecode
============================================= =============================================
Because we might support other ways to retrieve the metadata file in the future, Because we might support other ways to retrieve the metadata file in the future,
the mapping ``{"bzzr0": <Swarm hash>, "solc": <compiler version>}`` is stored the mapping ``{"bzzr1": <Swarm hash>, "solc": <compiler version>}`` is stored
`CBOR <https://tools.ietf.org/html/rfc7049>`_-encoded. Since the mapping might `CBOR <https://tools.ietf.org/html/rfc7049>`_-encoded. Since the mapping might
contain more keys (see below) and the beginning of that contain more keys (see below) and the beginning of that
encoding is not easy to find, its length is added in a two-byte big-endian encoding is not easy to find, its length is added in a two-byte big-endian
@ -132,7 +132,7 @@ encoding. The current version of the Solidity compiler usually adds the followin
to the end of the deployed bytecode:: to the end of the deployed bytecode::
0xa2 0xa2
0x65 'b' 'z' 'z' 'r' '0' 0x58 0x20 <32 bytes swarm hash> 0x65 'b' 'z' 'z' 'r' '1' 0x58 0x20 <32 bytes swarm hash>
0x64 's' 'o' 'l' 'c' 0x43 <3 byte version encoding> 0x64 's' 'o' 'l' 'c' 0x43 <3 byte version encoding>
0x00 0x32 0x00 0x32
@ -150,9 +150,9 @@ will instead use a complete version string including commit hash and build date.
are used, the mapping will also contain ``"experimental": true``. are used, the mapping will also contain ``"experimental": true``.
.. note:: .. note::
The compiler currently uses the "swarm version 0" hash of the metadata, The compiler currently uses the "swarm version 1" hash of the metadata,
but this might change in the future, so do not rely on this sequence but this might change in the future, so do not rely on this sequence
to start with ``0xa2 0x65 'b' 'z' 'z' 'r' '0'``. We might also to start with ``0xa2 0x65 'b' 'z' 'z' 'r' '1'``. We might also
add additional data to this CBOR structure, so the add additional data to this CBOR structure, so the
best option is to use a proper CBOR parser. best option is to use a proper CBOR parser.

View File

@ -27,6 +27,9 @@
#include <libdevcore/UTF8.h> #include <libdevcore/UTF8.h>
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
#include <vector>
#include <algorithm>
using namespace std; using namespace std;
using namespace langutil; using namespace langutil;
@ -259,7 +262,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node)
make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()), make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()),
make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)), make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)),
make_pair("baseContracts", toJson(_node.baseContracts())), make_pair("baseContracts", toJson(_node.baseContracts())),
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies)), make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies, true)),
make_pair("nodes", toJson(_node.subNodes())), make_pair("nodes", toJson(_node.subNodes())),
make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))
}); });

View File

@ -29,6 +29,8 @@
#include <json/json.h> #include <json/json.h>
#include <ostream> #include <ostream>
#include <stack> #include <stack>
#include <vector>
#include <algorithm>
namespace langutil namespace langutil
{ {
@ -148,15 +150,23 @@ private:
return _node.id(); return _node.id();
} }
template<class Container> template<class Container>
static Json::Value getContainerIds(Container const& container) static Json::Value getContainerIds(Container const& _container, bool _order = false)
{ {
Json::Value tmp(Json::arrayValue); std::vector<int> tmp;
for (auto const& element: container)
for (auto const& element: _container)
{ {
solAssert(element, ""); solAssert(element, "");
tmp.append(nodeId(*element)); tmp.push_back(nodeId(*element));
} }
return tmp; if (_order)
std::sort(tmp.begin(), tmp.end());
Json::Value json(Json::arrayValue);
for (int val: tmp)
json.append(val);
return json;
} }
static Json::Value typePointerToJson(TypePointer _tp, bool _short = false); static Json::Value typePointerToJson(TypePointer _tp, bool _short = false);
static Json::Value typePointerToJson(boost::optional<FuncCallArguments> const& _tps); static Json::Value typePointerToJson(boost::optional<FuncCallArguments> const& _tps);

View File

@ -26,7 +26,7 @@ parts:
source: . source: .
source-type: git source-type: git
plugin: cmake plugin: cmake
build-packages: [build-essential, libboost-all-dev, libcvc4-dev] build-packages: [build-essential, libboost-all-dev]
stage-packages: [libicu60] stage-packages: [libicu60]
override-build: | override-build: |
if git describe --exact-match --tags 2> /dev/null if git describe --exact-match --tags 2> /dev/null
@ -34,7 +34,7 @@ parts:
echo -n > ../src/prerelease.txt echo -n > ../src/prerelease.txt
fi fi
snapcraftctl build snapcraftctl build
after: [z3] after: [z3, cvc4]
z3: z3:
source: https://github.com/Z3Prover/z3.git source: https://github.com/Z3Prover/z3.git
source-tag: z3-4.8.4 source-tag: z3-4.8.4
@ -47,3 +47,16 @@ parts:
cd build cd build
make -j -l $(grep -c "^processor" /proc/cpuinfo) make -j -l $(grep -c "^processor" /proc/cpuinfo)
make install DESTDIR=$SNAPCRAFT_PART_INSTALL make install DESTDIR=$SNAPCRAFT_PART_INSTALL
cvc4:
source: https://github.com/CVC4/CVC4.git
source-tag: "1.7"
plugin: nil
build-packages: [python, cmake, openjdk-11-jre, libgmp-dev]
override-build: |
./contrib/get-antlr-3.4
./configure.sh --prefix=$SNAPCRAFT_STAGE/usr
cd build
make -j -l $(grep -c "^processor" /proc/cpuinfo)
make install
mkdir -p $SNAPCRAFT_PART_INSTALL/usr/lib/
cp $SNAPCRAFT_STAGE/usr/lib/libcvc4.so.6 $SNAPCRAFT_PART_INSTALL/usr/lib/

View File

@ -62,11 +62,15 @@ bool TestCase::validateSettings(langutil::EVMVersion)
return true; return true;
} }
pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream) pair<map<string, string>, size_t> TestCase::parseSourcesAndSettingsWithLineNumbers(istream& _stream)
{ {
string source; map<string, string> sources;
string currentSourceName;
string currentSource;
string line; string line;
size_t lineNumber = 1; size_t lineNumber = 1;
static string const sourceDelimiterStart("==== Source:");
static string const sourceDelimiterEnd("====");
static string const comment("// "); static string const comment("// ");
static string const settingsDelimiter("// ===="); static string const settingsDelimiter("// ====");
static string const delimiter("// ----"); static string const delimiter("// ----");
@ -80,7 +84,22 @@ pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _s
else if (boost::algorithm::starts_with(line, settingsDelimiter)) else if (boost::algorithm::starts_with(line, settingsDelimiter))
sourcePart = false; sourcePart = false;
else if (sourcePart) else if (sourcePart)
source += line + "\n"; {
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)) else if (boost::algorithm::starts_with(line, comment))
{ {
size_t colon = line.find(':'); size_t colon = line.find(':');
@ -95,12 +114,26 @@ pair<string, size_t> TestCase::parseSourceAndSettingsWithLineNumbers(istream& _s
else else
throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source."));
} }
return make_pair(source, lineNumber); 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) string TestCase::parseSourceAndSettings(istream& _stream)
{ {
return get<0>(parseSourceAndSettingsWithLineNumbers(_stream)); return parseSourceAndSettingsWithLineNumbers(_stream).first;
} }
string TestCase::parseSimpleExpectations(std::istream& _file) string TestCase::parseSimpleExpectations(std::istream& _file)

View File

@ -80,6 +80,8 @@ public:
virtual bool validateSettings(langutil::EVMVersion /*_evmVersion*/); virtual bool validateSettings(langutil::EVMVersion /*_evmVersion*/);
protected: 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::pair<std::string, std::size_t> parseSourceAndSettingsWithLineNumbers(std::istream& _file);
std::string parseSourceAndSettings(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); static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c);

View File

@ -0,0 +1,233 @@
{
"absolutePath" : "a",
"exportedSymbols" :
{
"A" :
[
1
],
"B" :
[
4
],
"C" :
[
7
],
"D" :
[
10
],
"E" :
[
13
]
},
"id" : 14,
"nodeType" : "SourceUnit",
"nodes" :
[
{
"baseContracts" : [],
"contractDependencies" : [],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 1,
"linearizedBaseContracts" :
[
1
],
"name" : "A",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "0:14:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 2,
"name" : "A",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 1,
"src" : "29:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_A_$1",
"typeString" : "contract A"
}
},
"id" : 3,
"nodeType" : "InheritanceSpecifier",
"src" : "29:1:1"
}
],
"contractDependencies" :
[
1
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 4,
"linearizedBaseContracts" :
[
4,
1
],
"name" : "B",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "15:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 5,
"name" : "B",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 4,
"src" : "49:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_B_$4",
"typeString" : "contract B"
}
},
"id" : 6,
"nodeType" : "InheritanceSpecifier",
"src" : "49:1:1"
}
],
"contractDependencies" :
[
1,
4
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 7,
"linearizedBaseContracts" :
[
7,
4,
1
],
"name" : "C",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "35:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 8,
"name" : "C",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 7,
"src" : "69:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_C_$7",
"typeString" : "contract C"
}
},
"id" : 9,
"nodeType" : "InheritanceSpecifier",
"src" : "69:1:1"
}
],
"contractDependencies" :
[
1,
4,
7
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 10,
"linearizedBaseContracts" :
[
10,
7,
4,
1
],
"name" : "D",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "55:19:1"
},
{
"baseContracts" :
[
{
"arguments" : null,
"baseName" :
{
"contractScope" : null,
"id" : 11,
"name" : "D",
"nodeType" : "UserDefinedTypeName",
"referencedDeclaration" : 10,
"src" : "89:1:1",
"typeDescriptions" :
{
"typeIdentifier" : "t_contract$_D_$10",
"typeString" : "contract D"
}
},
"id" : 12,
"nodeType" : "InheritanceSpecifier",
"src" : "89:1:1"
}
],
"contractDependencies" :
[
1,
4,
7,
10
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"id" : 13,
"linearizedBaseContracts" :
[
13,
10,
7,
4,
1
],
"name" : "E",
"nodeType" : "ContractDefinition",
"nodes" : [],
"scope" : 14,
"src" : "75:19:1"
}
],
"src" : "0:95:1"
}

View File

@ -0,0 +1,7 @@
contract A { }
contract B is A { }
contract C is B { }
contract D is C { }
contract E is D { }
// ----

View File

@ -0,0 +1,288 @@
{
"attributes" :
{
"absolutePath" : "a",
"exportedSymbols" :
{
"A" :
[
1
],
"B" :
[
4
],
"C" :
[
7
],
"D" :
[
10
],
"E" :
[
13
]
}
},
"children" :
[
{
"attributes" :
{
"baseContracts" :
[
null
],
"contractDependencies" :
[
null
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
1
],
"name" : "A",
"nodes" :
[
null
],
"scope" : 14
},
"id" : 1,
"name" : "ContractDefinition",
"src" : "0:14:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
4,
1
],
"name" : "B",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "A",
"referencedDeclaration" : 1,
"type" : "contract A"
},
"id" : 2,
"name" : "UserDefinedTypeName",
"src" : "29:1:1"
}
],
"id" : 3,
"name" : "InheritanceSpecifier",
"src" : "29:1:1"
}
],
"id" : 4,
"name" : "ContractDefinition",
"src" : "15:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
7,
4,
1
],
"name" : "C",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "B",
"referencedDeclaration" : 4,
"type" : "contract B"
},
"id" : 5,
"name" : "UserDefinedTypeName",
"src" : "49:1:1"
}
],
"id" : 6,
"name" : "InheritanceSpecifier",
"src" : "49:1:1"
}
],
"id" : 7,
"name" : "ContractDefinition",
"src" : "35:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4,
7
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
10,
7,
4,
1
],
"name" : "D",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "C",
"referencedDeclaration" : 7,
"type" : "contract C"
},
"id" : 8,
"name" : "UserDefinedTypeName",
"src" : "69:1:1"
}
],
"id" : 9,
"name" : "InheritanceSpecifier",
"src" : "69:1:1"
}
],
"id" : 10,
"name" : "ContractDefinition",
"src" : "55:19:1"
},
{
"attributes" :
{
"contractDependencies" :
[
1,
4,
7,
10
],
"contractKind" : "contract",
"documentation" : null,
"fullyImplemented" : true,
"linearizedBaseContracts" :
[
13,
10,
7,
4,
1
],
"name" : "E",
"nodes" :
[
null
],
"scope" : 14
},
"children" :
[
{
"attributes" :
{
"arguments" : null
},
"children" :
[
{
"attributes" :
{
"contractScope" : null,
"name" : "D",
"referencedDeclaration" : 10,
"type" : "contract D"
},
"id" : 11,
"name" : "UserDefinedTypeName",
"src" : "89:1:1"
}
],
"id" : 12,
"name" : "InheritanceSpecifier",
"src" : "89:1:1"
}
],
"id" : 13,
"name" : "ContractDefinition",
"src" : "75:19:1"
}
],
"id" : 14,
"name" : "SourceUnit",
"src" : "0:95:1"
}

View File

@ -1 +1,3 @@
contract C1 {} contract C2 is C1 {} contract C1 {} contract C2 is C1 {}
// ----

View File

@ -41,183 +41,6 @@ namespace test
BOOST_AUTO_TEST_SUITE(SolidityImports) BOOST_AUTO_TEST_SUITE(SolidityImports)
BOOST_AUTO_TEST_CASE(smoke_test)
{
CompilerStack c;
c.setSources({{"a", "contract C {} pragma solidity >=0.0;"}});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(regular_import)
{
CompilerStack c;
c.setSources({
{"a", "contract C {} pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(import_does_not_clutter_importee)
{
CompilerStack c;
c.setSources({
{"a", "contract C { D d; } pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(import_is_transitive)
{
CompilerStack c;
c.setSources({
{"a", "contract C { } pragma solidity >=0.0;"},
{"b", "import \"a\"; pragma solidity >=0.0;"},
{"c", "import \"b\"; contract D is C {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(circular_import)
{
CompilerStack c;
c.setSources({
{"a", "import \"b\"; contract C { D d; } pragma solidity >=0.0;"},
{"b", "import \"a\"; contract D { C c; } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(relative_import)
{
CompilerStack c;
c.setSources({
{"a", "import \"./dir/b\"; contract A is B {} pragma solidity >=0.0;"},
{"dir/b", "contract B {} pragma solidity >=0.0;"},
{"dir/c", "import \"../a\"; contract C is A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(relative_import_multiplex)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"dir/a/b/c", "import \"../../.././a\"; contract B is A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(simple_alias)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"dir/a/b/c", "import \"../../.././a\" as x; contract B is x.A { function() external { x.A r = x.A(20); } } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(library_name_clash)
{
CompilerStack c;
c.setSources({
{"a", "library A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"},
{"c", "import {A} from \"./a\"; import {A} from \"./b\";"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(library_name_clash_with_contract)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(complex_import)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} contract B {} contract C { struct S { uint a; } } pragma solidity >=0.0;"},
{"b", "import \"a\" as x; import {B as b, C as c, C} from \"a\"; "
"contract D is b { function f(c.S memory var1, x.C.S memory var2, C.S memory var3) internal {} } pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_1)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import \"a\"; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_2)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import \"a\" as A; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_3)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A as b} from \"a\"; contract b {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_4)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A} from \"a\"; contract A {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(name_clash_in_import_5)
{
CompilerStack c;
c.setSources({
{"a", "contract A {} pragma solidity >=0.0;"},
{"b", "import {A} from \"a\"; contract B {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
}
BOOST_AUTO_TEST_CASE(remappings) BOOST_AUTO_TEST_CASE(remappings)
{ {
CompilerStack c; CompilerStack c;
@ -246,17 +69,6 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings)
BOOST_CHECK(c.compile()); BOOST_CHECK(c.compile());
} }
BOOST_AUTO_TEST_CASE(filename_with_period)
{
CompilerStack c;
c.setSources({
{"a/a.sol", "import \".b.sol\"; contract A is B {} pragma solidity >=0.0;"},
{"a/.b.sol", "contract B {} pragma solidity >=0.0;"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_preserved) BOOST_AUTO_TEST_CASE(context_dependent_remappings_ensure_default_and_module_preserved)
{ {
CompilerStack c; CompilerStack c;
@ -303,245 +115,6 @@ BOOST_AUTO_TEST_CASE(context_dependent_remappings_order_independent_2)
BOOST_CHECK(c.compile()); BOOST_CHECK(c.compile());
} }
BOOST_AUTO_TEST_CASE(shadowing_via_import)
{
CompilerStack c;
c.setSources({
{"a", "library A {} pragma solidity >=0.0;"},
{"b", "library A {} pragma solidity >=0.0;"},
{"c", "import {A} from \"./a\"; import {A} from \"./b\";"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
}
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_imports)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract X {} pragma solidity >=0.0;"},
{"b", R"(
pragma solidity >=0.0;
import * as msg from "B.sol";
contract C {
})"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
size_t errorCount = 0;
for (auto const& e: c.errors())
{
string const* msg = e->comment();
BOOST_REQUIRE(msg);
if (msg->find("pre-release") != string::npos)
continue;
BOOST_CHECK(
msg->find("shadows a builtin symbol") != string::npos
);
errorCount++;
}
BOOST_CHECK_EQUAL(errorCount, 1);
}
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_multiple_imports)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract msg {} contract block{} pragma solidity >=0.0;"},
{"b", R"(
pragma solidity >=0.0;
import {msg, block} from "B.sol";
contract C {
})"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
auto numErrors = c.errors().size();
// Sometimes we get the prerelease warning, sometimes not.
BOOST_CHECK(4 <= numErrors && numErrors <= 5);
for (auto const& e: c.errors())
{
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK(
msg->find("pre-release") != string::npos ||
msg->find("shadows a builtin symbol") != string::npos
);
}
}
BOOST_AUTO_TEST_CASE(shadowing_builtins_with_alias)
{
CompilerStack c;
c.setSources({
{"B.sol", "contract C {} pragma solidity >=0.0;"},
{"b", R"(
pragma solidity >=0.0;
import {C as msg} from "B.sol";)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
auto numErrors = c.errors().size();
// Sometimes we get the prerelease warning, sometimes not.
BOOST_CHECK(1 <= numErrors && numErrors <= 2);
for (auto const& e: c.errors())
{
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK(
msg->find("pre-release") != string::npos ||
msg->find("shadows a builtin symbol") != string::npos
);
}
}
BOOST_AUTO_TEST_CASE(inheritance_abi_encoder_mismatch_1)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK_EQUAL(*msg, std::string("Contract \"C\" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature."));
}
BOOST_CHECK_EQUAL(typeErrors, 1);
}
BOOST_AUTO_TEST_CASE(inheritance_abi_encoder_mismatch_2)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(!c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
string const* msg = e->comment();
BOOST_REQUIRE(msg);
BOOST_CHECK_EQUAL(*msg, std::string("Contract \"B\" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature."));
}
BOOST_CHECK_EQUAL(typeErrors, 1);
}
BOOST_AUTO_TEST_CASE(inheritance_abi_encoder_match)
{
CompilerStack c;
c.setSources({
{"A.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
)"},
{"B.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
)"},
{"C.sol", R"(
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
import "./B.sol";
contract C is B { }
)"}
});
c.setEVMVersion(dev::test::Options::get().evmVersion());
BOOST_CHECK(c.compile());
int typeErrors = 0;
// Sometimes we get the prerelease warning, sometimes not.
for (auto const& e: c.errors())
{
if (e->type() != langutil::Error::Type::TypeError)
continue;
typeErrors++;
}
BOOST_CHECK_EQUAL(typeErrors, 0);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -116,13 +116,15 @@ BOOST_AUTO_TEST_CASE(division)
if (a == 0) { if (a == 0) {
return 0; return 0;
} }
// TODO remove when SMTChecker sees that this code is the `else` of the `return`.
require(a != 0);
uint256 c = a * b; uint256 c = a * b;
require(c / a == b); require(c / a == b);
return c; return c;
} }
} }
)"; )";
CHECK_WARNING(text, "Division by zero"); CHECK_SUCCESS_OR_WARNING(text, "might happen");
text = R"( text = R"(
contract C { contract C {
function div(uint256 a, uint256 b) internal pure returns (uint256) { function div(uint256 a, uint256 b) internal pure returns (uint256) {

View File

@ -108,6 +108,9 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end.")); BOOST_THROW_EXCEPTION(runtime_error("Error must have a SourceLocation with start and end."));
int start = location["start"].asInt(); int start = location["start"].asInt();
int end = location["end"].asInt(); int end = location["end"].asInt();
std::string sourceName;
if (location.isMember("source") && location["source"].isString())
sourceName = location["source"].asString();
if (start >= static_cast<int>(versionPragma.size())) if (start >= static_cast<int>(versionPragma.size()))
start -= versionPragma.size(); start -= versionPragma.size();
if (end >= static_cast<int>(versionPragma.size())) if (end >= static_cast<int>(versionPragma.size()))
@ -115,6 +118,7 @@ TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePr
m_errorList.emplace_back(SyntaxTestError{ m_errorList.emplace_back(SyntaxTestError{
error["type"].asString(), error["type"].asString(),
error["message"].asString(), error["message"].asString(),
sourceName,
start, start,
end end
}); });
@ -141,13 +145,20 @@ vector<string> SMTCheckerTest::hashesFromJson(Json::Value const& _jsonObj, strin
Json::Value SMTCheckerTest::buildJson(string const& _extra) Json::Value SMTCheckerTest::buildJson(string const& _extra)
{ {
string language = "\"language\": \"Solidity\""; string language = "\"language\": \"Solidity\"";
string sourceName = "\"A\""; string sources = " \"sources\": { ";
string sourceContent = "\"" + _extra + m_source + "\""; bool first = true;
string sourceObj = "{ \"content\": " + sourceContent + "}"; for (auto [sourceName, sourceContent]: m_sources)
string sources = " \"sources\": { " + sourceName + ": " + sourceObj + "}"; {
string sourceObj = "{ \"content\": \"" + _extra + sourceContent + "\"}";
if (!first)
sources += ", ";
sources += "\"" + sourceName + "\": " + sourceObj;
first = false;
}
sources += "}";
string input = "{" + language + ", " + sources + "}"; string input = "{" + language + ", " + sources + "}";
Json::Value source; Json::Value source;
if (!jsonParse(input, source)) if (!jsonParse(input, source))
BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string.")); BOOST_THROW_EXCEPTION(runtime_error("Could not build JSON from string: " + input));
return source; return source;
} }

View File

@ -59,7 +59,8 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion
BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\"."));
file.exceptions(ios::badbit); file.exceptions(ios::badbit);
m_source = parseSourceAndSettings(file); m_sources = parseSourcesAndSettings(file);
if (m_settings.count("optimize-yul")) if (m_settings.count("optimize-yul"))
{ {
m_optimiseYul = true; m_optimiseYul = true;
@ -74,7 +75,10 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
{ {
string const versionPragma = "pragma solidity >=0.0;\n"; string const versionPragma = "pragma solidity >=0.0;\n";
compiler().reset(); compiler().reset();
compiler().setSources({{"", versionPragma + m_source}}); auto sourcesWithPragma = m_sources;
for (auto& source: sourcesWithPragma)
source.second = versionPragma + source.second;
compiler().setSources(sourcesWithPragma);
compiler().setEVMVersion(m_evmVersion); compiler().setEVMVersion(m_evmVersion);
compiler().setParserErrorRecovery(m_parserErrorRecovery); compiler().setParserErrorRecovery(m_parserErrorRecovery);
compiler().setOptimiserSettings( compiler().setOptimiserSettings(
@ -83,11 +87,27 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
OptimiserSettings::minimal() OptimiserSettings::minimal()
); );
if (compiler().parse()) if (compiler().parse())
compiler().analyze(); if (compiler().analyze())
try
{
if (!compiler().compile())
BOOST_THROW_EXCEPTION(runtime_error("Compilation failed even though analysis was successful."));
}
catch (UnimplementedFeatureError const& _e)
{
m_errorList.emplace_back(SyntaxTestError{
"UnimplementedFeatureError",
errorMessage(_e),
"",
-1,
-1
});
}
for (auto const& currentError: filterErrors(compiler().errors(), true)) for (auto const& currentError: filterErrors(compiler().errors(), true))
{ {
int locationStart = -1, locationEnd = -1; int locationStart = -1, locationEnd = -1;
string sourceName;
if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError)) if (auto location = boost::get_error_info<errinfo_sourceLocation>(*currentError))
{ {
// ignore the version pragma inserted by the testing tool when calculating locations. // ignore the version pragma inserted by the testing tool when calculating locations.
@ -95,10 +115,13 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix
locationStart = location->start - versionPragma.size(); locationStart = location->start - versionPragma.size();
if (location->end >= static_cast<int>(versionPragma.size())) if (location->end >= static_cast<int>(versionPragma.size()))
locationEnd = location->end - versionPragma.size(); locationEnd = location->end - versionPragma.size();
if (location->source)
sourceName = location->source->name();
} }
m_errorList.emplace_back(SyntaxTestError{ m_errorList.emplace_back(SyntaxTestError{
currentError->typeName(), currentError->typeName(),
errorMessage(*currentError), errorMessage(*currentError),
sourceName,
locationStart, locationStart,
locationEnd locationEnd
}); });
@ -123,17 +146,26 @@ bool SyntaxTest::printExpectationAndError(ostream& _stream, string const& _lineP
void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const
{ {
if (_formatted)
{ if (m_sources.empty())
if (m_source.empty())
return; return;
vector<char const*> sourceFormatting(m_source.length(), formatting::RESET); bool outputSourceNames = true;
for (auto const& error: m_errorList) if (m_sources.size() == 1 && m_sources.begin()->first.empty())
if (error.locationStart >= 0 && error.locationEnd >= 0) outputSourceNames = false;
if (_formatted)
{ {
assert(static_cast<size_t>(error.locationStart) <= m_source.length()); for (auto const& [name, source]: m_sources)
assert(static_cast<size_t>(error.locationEnd) <= m_source.length()); {
if (outputSourceNames)
_stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl;
vector<char const*> sourceFormatting(source.length(), formatting::RESET);
for (auto const& error: m_errorList)
if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0)
{
assert(static_cast<size_t>(error.locationStart) <= source.length());
assert(static_cast<size_t>(error.locationEnd) <= source.length());
bool isWarning = error.type == "Warning"; bool isWarning = error.type == "Warning";
for (int i = error.locationStart; i < error.locationEnd; i++) for (int i = error.locationStart; i < error.locationEnd; i++)
if (isWarning) if (isWarning)
@ -145,25 +177,30 @@ void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _
sourceFormatting[i] = formatting::RED_BACKGROUND; sourceFormatting[i] = formatting::RED_BACKGROUND;
} }
_stream << _linePrefix << sourceFormatting.front() << m_source.front(); _stream << _linePrefix << sourceFormatting.front() << source.front();
for (size_t i = 1; i < m_source.length(); i++) for (size_t i = 1; i < source.length(); i++)
{ {
if (sourceFormatting[i] != sourceFormatting[i - 1]) if (sourceFormatting[i] != sourceFormatting[i - 1])
_stream << sourceFormatting[i]; _stream << sourceFormatting[i];
if (m_source[i] != '\n') if (source[i] != '\n')
_stream << m_source[i]; _stream << source[i];
else else
{ {
_stream << formatting::RESET << endl; _stream << formatting::RESET << endl;
if (i + 1 < m_source.length()) if (i + 1 < source.length())
_stream << _linePrefix << sourceFormatting[i]; _stream << _linePrefix << sourceFormatting[i];
} }
} }
_stream << formatting::RESET; _stream << formatting::RESET;
} }
}
else else
for (auto const& [name, source]: m_sources)
{ {
stringstream stream(m_source); if (outputSourceNames)
_stream << _linePrefix << "==== Source: " + name << " ====" << endl;
stringstream stream(source);
string line; string line;
while (getline(stream, line)) while (getline(stream, line))
_stream << _linePrefix << line << endl; _stream << _linePrefix << line << endl;
@ -187,9 +224,11 @@ void SyntaxTest::printErrorList(
_stream << _linePrefix; _stream << _linePrefix;
_stream << error.type << ": "; _stream << error.type << ": ";
} }
if (error.locationStart >= 0 || error.locationEnd >= 0) if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0)
{ {
_stream << "("; _stream << "(";
if (!error.sourceName.empty())
_stream << error.sourceName << ":";
if (error.locationStart >= 0) if (error.locationStart >= 0)
_stream << error.locationStart; _stream << error.locationStart;
_stream << "-"; _stream << "-";
@ -234,10 +273,19 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
int locationStart = -1; int locationStart = -1;
int locationEnd = -1; int locationEnd = -1;
std::string sourceName;
if (it != line.end() && *it == '(') if (it != line.end() && *it == '(')
{ {
++it; ++it;
if (it != line.end() && !isdigit(*it))
{
auto sourceNameStart = it;
while (it != line.end() && *it != ':')
++it;
sourceName = std::string(sourceNameStart, it);
expect(it, line.end(), ':');
}
locationStart = parseUnsignedInteger(it, line.end()); locationStart = parseUnsignedInteger(it, line.end());
expect(it, line.end(), '-'); expect(it, line.end(), '-');
locationEnd = parseUnsignedInteger(it, line.end()); locationEnd = parseUnsignedInteger(it, line.end());
@ -251,6 +299,7 @@ vector<SyntaxTestError> SyntaxTest::parseExpectations(istream& _stream)
expectations.emplace_back(SyntaxTestError{ expectations.emplace_back(SyntaxTestError{
move(errorType), move(errorType),
move(errorMessage), move(errorMessage),
move(sourceName),
locationStart, locationStart,
locationEnd locationEnd
}); });

View File

@ -38,12 +38,14 @@ struct SyntaxTestError
{ {
std::string type; std::string type;
std::string message; std::string message;
std::string sourceName;
int locationStart; int locationStart;
int locationEnd; int locationEnd;
bool operator==(SyntaxTestError const& _rhs) const bool operator==(SyntaxTestError const& _rhs) const
{ {
return type == _rhs.type && return type == _rhs.type &&
message == _rhs.message && message == _rhs.message &&
sourceName == _rhs.sourceName &&
locationStart == _rhs.locationStart && locationStart == _rhs.locationStart &&
locationEnd == _rhs.locationEnd; locationEnd == _rhs.locationEnd;
} }
@ -85,7 +87,7 @@ protected:
static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream); static std::vector<SyntaxTestError> parseExpectations(std::istream& _stream);
std::string m_source; std::map<std::string, std::string> m_sources;
std::vector<SyntaxTestError> m_expectations; std::vector<SyntaxTestError> m_expectations;
std::vector<SyntaxTestError> m_errorList; std::vector<SyntaxTestError> m_errorList;
bool m_optimiseYul = false; bool m_optimiseYul = false;

View File

@ -1,3 +1,4 @@
==== Source: A ====
pragma experimental SMTChecker; pragma experimental SMTChecker;
contract C contract C

View File

@ -1,3 +1,4 @@
==== Source: A ====
pragma experimental SMTChecker; pragma experimental SMTChecker;
contract C contract C

View File

@ -4,3 +4,5 @@ contract C {
fixed a3 = 0 / 0.123; fixed a3 = 0 / 0.123;
fixed a4 = 0 / -0.123; fixed a4 = 0 / -0.123;
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -0,0 +1,4 @@
==== Source: a ====
import "b"; contract C { D d; }
==== Source: b ====
import "a"; contract D { C c; }

View File

@ -0,0 +1,5 @@
==== Source: a ====
contract A {} contract B {} contract C { struct S { uint a; } }
==== Source: b ====
import "a" as x; import {B as b, C as c, C} from "a";
contract D is b { function f(c.S memory var1, x.C.S memory var2, C.S memory var3) internal {} }

View File

@ -0,0 +1,6 @@
==== Source: a/.b.sol ====
contract B {}
==== Source: a/a.sol ====
import ".b.sol"; contract A is B {}
// ----
// ParserError: (a/a.sol:0-16): Source ".b.sol" not found: File not supplied initially.

View File

@ -0,0 +1,6 @@
==== Source: a ====
contract C { D d; }
==== Source: b ====
import "a"; contract D is C {}
// ----
// DeclarationError: (a:13-14): Identifier not found or not unique.

View File

@ -0,0 +1,7 @@
==== Source: a ====
contract C { }
==== Source: b ====
import "a";
==== Source: c ====
import "b";
contract D is C {}

View File

@ -0,0 +1,23 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
pragma experimental ABIEncoderV2;
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (B.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (C.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.

View File

@ -0,0 +1,21 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
pragma experimental ABIEncoderV2;
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (B.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (C.sol:18-37): Contract "C" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.

View File

@ -0,0 +1,18 @@
==== Source: A.sol ====
pragma experimental ABIEncoderV2;
contract A
{
struct S { uint a; }
S public s;
function f(S memory _s) public returns (S memory,S memory) { }
}
==== Source: B.sol ====
import "./A.sol";
contract B is A { }
==== Source: C.sol ====
import "./B.sol";
contract C is B { }
// ----
// Warning: (A.sol:0-33): Experimental features are turned on. Do not use experimental features on live deployments.
// TypeError: (B.sol:18-37): Contract "B" does not use the new experimental ABI encoder but wants to inherit from a contract which uses types that require it. Use "pragma experimental ABIEncoderV2;" for the inheriting contract as well to enable the feature.

View File

@ -0,0 +1,8 @@
==== Source: a ====
library A {}
==== Source: b ====
library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.

View File

@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: b ====
library A {}

View File

@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import "a"; contract A {}
// ----
// DeclarationError: (b:12-25): Identifier already declared.

View File

@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import "a" as A; contract A {}
// ----
// DeclarationError: (b:17-30): Identifier already declared.

View File

@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A as b} from "a"; contract b {}
// ----
// DeclarationError: (b:26-39): Identifier already declared.

View File

@ -0,0 +1,6 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A} from "a"; contract A {}
// ----
// DeclarationError: (b:21-34): Identifier already declared.

View File

@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: b ====
import {A} from "a"; contract B {}

View File

@ -0,0 +1,4 @@
==== Source: a ====
contract C {}
==== Source: b ====
import "a"; contract D is C {}

View File

@ -0,0 +1,6 @@
==== Source: a ====
import "./dir/b"; contract A is B {}
==== Source: dir/b ====
contract B {}
==== Source: dir/c ====
import "../a"; contract C is A {}

View File

@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: dir/a/b/c ====
import "../../.././a"; contract B is A {}

View File

@ -0,0 +1,6 @@
==== Source: B.sol ====
contract C {}
==== Source: b ====
import {C as msg} from "B.sol";
// ----
// Warning: (B.sol:0-13): This declaration shadows a builtin symbol.

View File

@ -0,0 +1,8 @@
==== Source: B.sol ====
contract X {}
==== Source: b ====
import * as msg from "B.sol";
contract C {
}
// ----
// Warning: (b:0-29): This declaration shadows a builtin symbol.

View File

@ -0,0 +1,11 @@
==== Source: B.sol ====
contract msg {} contract block{}
==== Source: b ====
import {msg, block} from "B.sol";
contract C {
}
// ----
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.
// Warning: (B.sol:0-15): This declaration shadows a builtin symbol.
// Warning: (B.sol:16-32): This declaration shadows a builtin symbol.

View File

@ -0,0 +1,8 @@
==== Source: a ====
library A {}
==== Source: b ====
library A {}
==== Source: c ====
import {A} from "./a"; import {A} from "./b";
// ----
// DeclarationError: (c:23-45): Identifier already declared.

View File

@ -0,0 +1,4 @@
==== Source: a ====
contract A {}
==== Source: dir/a/b/c ====
import "../../.././a" as x; contract B is x.A { function() external { x.A r = x.A(20); r; } }

View File

@ -0,0 +1,2 @@
==== Source: a ====
contract C {}

View File

@ -4,5 +4,6 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-67): Unused local variable. // Warning: (50-67): Unused local variable.
// Warning: (20-119): Function state mutability can be restricted to pure // Warning: (20-119): Function state mutability can be restricted to pure

View File

@ -4,5 +4,6 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-73): Unused local variable. // Warning: (50-73): Unused local variable.
// Warning: (20-118): Function state mutability can be restricted to pure // Warning: (20-118): Function state mutability can be restricted to pure

View File

@ -0,0 +1,10 @@
==== Source: A ====
contract A {
function g() public { x; }
}
==== Source: B ====
contract B {
function f() public { }
}
// ----
// DeclarationError: (A:36-37): Undeclared identifier.

View File

@ -0,0 +1,12 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
import "A";
contract B is A {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// Warning: (A:14-78): Function state mutability can be restricted to pure
// Warning: (B:31-95): Function state mutability can be restricted to pure

View File

@ -0,0 +1,5 @@
==== Source: a ====
import "b";
contract C {}
// ----
// ParserError: (a:0-11): Source "b" not found: File not supplied initially.

View File

@ -0,0 +1,10 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
contract B is A {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// DeclarationError: (B:14-15): Identifier not found or not unique.

View File

@ -0,0 +1,7 @@
==== Source: SourceName ====
contract A {
uint256 x;
function f() public pure { x = 42; }
}
// ----
// TypeError: (SourceName:53-54): Function declared as pure, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.

View File

@ -0,0 +1,11 @@
==== Source: A ====
contract A {
function g(uint256 x) public view returns(uint256) { return x; }
}
==== Source: B ====
contract B {
function f(uint256 x) public view returns(uint256) { return x; }
}
// ----
// Warning: (A:14-78): Function state mutability can be restricted to pure
// Warning: (B:14-78): Function state mutability can be restricted to pure

View File

@ -8,4 +8,5 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-147): Function state mutability can be restricted to pure // Warning: (20-147): Function state mutability can be restricted to pure

View File

@ -6,4 +6,5 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-104): Function state mutability can be restricted to pure // Warning: (20-104): Function state mutability can be restricted to pure

View File

@ -6,4 +6,5 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-108): Function state mutability can be restricted to pure // Warning: (20-108): Function state mutability can be restricted to pure

View File

@ -5,3 +5,5 @@ contract test {
a; b; a; b;
} }
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -7,3 +7,5 @@ contract A {
a; b; c; d; a; b; c; d;
} }
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -5,4 +5,5 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-104): Function state mutability can be restricted to pure // Warning: (20-104): Function state mutability can be restricted to pure

View File

@ -6,4 +6,5 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (20-182): Function state mutability can be restricted to pure // Warning: (20-182): Function state mutability can be restricted to pure

View File

@ -4,3 +4,5 @@ contract test {
fixedString[0.5] = "Half"; fixedString[0.5] = "Half";
} }
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -5,3 +5,5 @@ contract test {
} }
myStruct a = myStruct(3.125, 3); myStruct a = myStruct(3.125, 3);
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -11,5 +11,6 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (238-252): This declaration shadows an existing declaration. // Warning: (238-252): This declaration shadows an existing declaration.
// Warning: (20-339): Function state mutability can be restricted to pure // Warning: (20-339): Function state mutability can be restricted to pure

View File

@ -4,5 +4,6 @@ contract test {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (50-58): Unused local variable. // Warning: (50-58): Unused local variable.
// Warning: (20-89): Function state mutability can be restricted to pure // Warning: (20-89): Function state mutability can be restricted to pure

View File

@ -6,6 +6,7 @@ contract A {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.
// Warning: (52-60): Unused function parameter. Remove or comment out the variable name to silence this warning. // Warning: (52-60): Unused function parameter. Remove or comment out the variable name to silence this warning.
// Warning: (62-74): Unused function parameter. Remove or comment out the variable name to silence this warning. // Warning: (62-74): Unused function parameter. Remove or comment out the variable name to silence this warning.
// Warning: (93-104): Unused local variable. // Warning: (93-104): Unused local variable.

View File

@ -7,3 +7,4 @@ contract C {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -6,3 +6,5 @@ contract test {
a; b; c; a; b; c;
} }
} }
// ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.

View File

@ -13,3 +13,4 @@ contract C {
} }
} }
// ---- // ----
// UnimplementedFeatureError: Not yet implemented - FixedPointType.