aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/contributing.rst2
-rw-r--r--libsolidity/analysis/TypeChecker.cpp76
-rw-r--r--libsolidity/ast/Types.cpp46
-rw-r--r--test/InteractiveTests.h63
-rw-r--r--test/boostTest.cpp58
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol3
-rw-r--r--test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol15
-rw-r--r--test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol1
-rw-r--r--test/tools/isoltest.cpp62
9 files changed, 174 insertions, 152 deletions
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 43b2fd38..12dea7d1 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -61,7 +61,7 @@ New features and bugfixes should be added to the ``Changelog.md`` file: please
follow the style of previous entries, when applicable.
Finally, please make sure you respect the `coding style
-<https://raw.githubusercontent.com/ethereum/solidity/develop/CODING_STYLE.md>`_
+<https://github.com/ethereum/solidity/blob/develop/CODING_STYLE.md>`_
for this project. Also, even though we do CI testing, please test your code and
ensure that it builds locally before submitting a pull request.
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 1c9f1956..d41415c0 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -935,30 +935,32 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
var.accept(*this);
if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type))
{
+ auto errorMsg = "Type " +
+ valueComponentType->toString() +
+ " is not implicitly convertible to expected type " +
+ var.annotation().type->toString();
if (
valueComponentType->category() == Type::Category::RationalNumber &&
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
valueComponentType->mobileType()
)
- m_errorReporter.typeError(
- _statement.location(),
- "Type " +
- valueComponentType->toString() +
- " is not implicitly convertible to expected type " +
- var.annotation().type->toString() +
- ". Try converting to type " +
- valueComponentType->mobileType()->toString() +
- " or use an explicit conversion."
- );
+ {
+ if (var.annotation().type->operator==(*valueComponentType->mobileType()))
+ m_errorReporter.typeError(
+ _statement.location(),
+ errorMsg + ", but it can be explicitly converted."
+ );
+ else
+ m_errorReporter.typeError(
+ _statement.location(),
+ errorMsg +
+ ". Try converting to type " +
+ valueComponentType->mobileType()->toString() +
+ " or use an explicit conversion."
+ );
+ }
else
- m_errorReporter.typeError(
- _statement.location(),
- "Type " +
- valueComponentType->toString() +
- " is not implicitly convertible to expected type " +
- var.annotation().type->toString() +
- "."
- );
+ m_errorReporter.typeError(_statement.location(), errorMsg + ".");
}
}
}
@@ -2331,30 +2333,32 @@ bool TypeChecker::expectType(Expression const& _expression, Type const& _expecte
_expression.accept(*this);
if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType))
{
+ auto errorMsg = "Type " +
+ type(_expression)->toString() +
+ " is not implicitly convertible to expected type " +
+ _expectedType.toString();
if (
type(_expression)->category() == Type::Category::RationalNumber &&
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
type(_expression)->mobileType()
)
- m_errorReporter.typeError(
- _expression.location(),
- "Type " +
- type(_expression)->toString() +
- " is not implicitly convertible to expected type " +
- _expectedType.toString() +
- ". Try converting to type " +
- type(_expression)->mobileType()->toString() +
- " or use an explicit conversion."
- );
+ {
+ if (_expectedType.operator==(*type(_expression)->mobileType()))
+ m_errorReporter.typeError(
+ _expression.location(),
+ errorMsg + ", but it can be explicitly converted."
+ );
+ else
+ m_errorReporter.typeError(
+ _expression.location(),
+ errorMsg +
+ ". Try converting to type " +
+ type(_expression)->mobileType()->toString() +
+ " or use an explicit conversion."
+ );
+ }
else
- m_errorReporter.typeError(
- _expression.location(),
- "Type " +
- type(_expression)->toString() +
- " is not implicitly convertible to expected type " +
- _expectedType.toString() +
- "."
- );
+ m_errorReporter.typeError(_expression.location(), errorMsg + ".");
return false;
}
return true;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index db7c492b..c35dde3c 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -125,6 +125,22 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2)
return fitsPrecisionBaseX(_mantissa, 1.0, _expBase2);
}
+/// Checks whether _value fits into IntegerType _type.
+bool fitsIntegerType(bigint const& _value, IntegerType const& _type)
+{
+ return (_type.minValue() <= _value) && (_value <= _type.maxValue());
+}
+
+/// Checks whether _value fits into _bits bits when having 1 bit as the sign bit
+/// if _signed is true.
+bool fitsIntoBits(bigint const& _value, unsigned _bits, bool _signed)
+{
+ return fitsIntegerType(_value, IntegerType(
+ _bits,
+ _signed ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned
+ ));
+}
+
}
void StorageOffsets::computeOffsets(TypePointers const& _types)
@@ -963,27 +979,21 @@ BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo)
if (isFractional())
return false;
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
- if (m_value == rational(0))
- return true;
- unsigned forSignBit = (targetType.isSigned() ? 1 : 0);
- if (m_value > rational(0))
- {
- if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit)))
- return true;
- return false;
- }
- if (targetType.isSigned())
- {
- if (-m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit)))
- return true;
- }
- return false;
+ return fitsIntegerType(m_value.numerator(), targetType);
}
case Category::FixedPoint:
{
- if (auto fixed = fixedPointType())
- return fixed->isImplicitlyConvertibleTo(_convertTo);
- return false;
+ FixedPointType const& targetType = dynamic_cast<FixedPointType const&>(_convertTo);
+ // Store a negative number into an unsigned.
+ if (isNegative() && !targetType.isSigned())
+ return false;
+ if (!isFractional())
+ return (targetType.minIntegerValue() <= m_value) && (m_value <= targetType.maxIntegerValue());
+ rational value = m_value * pow(bigint(10), targetType.fractionalDigits());
+ // Need explicit conversion since truncation will occur.
+ if (value.denominator() != 1)
+ return false;
+ return fitsIntoBits(value.numerator(), targetType.numBits(), targetType.isSigned());
}
case Category::FixedBytes:
return (m_value == rational(0)) || (m_compatibleBytesType && *m_compatibleBytesType == _convertTo);
diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h
new file mode 100644
index 00000000..be076059
--- /dev/null
+++ b/test/InteractiveTests.h
@@ -0,0 +1,63 @@
+/*
+ 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/>.
+*/
+
+#pragma once
+
+#include <test/TestCase.h>
+#include <test/libsolidity/ASTJSONTest.h>
+#include <test/libsolidity/SyntaxTest.h>
+#include <test/libsolidity/SMTCheckerJSONTest.h>
+#include <test/libyul/YulOptimizerTest.h>
+#include <test/libyul/ObjectCompilerTest.h>
+
+#include <boost/filesystem.hpp>
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+/** Container for all information regarding a testsuite */
+struct Testsuite
+{
+ char const* title;
+ boost::filesystem::path const path;
+ boost::filesystem::path const subpath;
+ bool smt;
+ bool ipc;
+ TestCase::TestCaseCreator testCaseCreator;
+};
+
+
+/// Array of testsuits that can be run interactively as well as automatically
+Testsuite const g_interactiveTestsuites[] = {
+/*
+ Title Path Subpath SMT IPC Creator function */
+ {"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
+ {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},
+ {"Syntax", "libsolidity", "syntaxTests", false, false, &SyntaxTest::create},
+ {"JSON AST", "libsolidity", "ASTJSON", false, false, &ASTJSONTest::create},
+ {"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SyntaxTest::create},
+ {"SMT Checker JSON", "libsolidity", "smtCheckerTestsJSON", true, false, &SMTCheckerTest::create}
+};
+
+}
+}
+}
+
diff --git a/test/boostTest.cpp b/test/boostTest.cpp
index ff443d11..034aaef3 100644
--- a/test/boostTest.cpp
+++ b/test/boostTest.cpp
@@ -35,16 +35,13 @@
#pragma GCC diagnostic pop
+#include <test/InteractiveTests.h>
#include <test/Options.h>
-#include <test/libsolidity/ASTJSONTest.h>
-#include <test/libsolidity/SyntaxTest.h>
-#include <test/libsolidity/SMTCheckerJSONTest.h>
-#include <test/libyul/YulOptimizerTest.h>
-#include <test/libyul/ObjectCompilerTest.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
+#include <string>
using namespace boost::unit_test;
using namespace dev::solidity::test;
@@ -129,46 +126,26 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
master_test_suite_t& master = framework::master_test_suite();
master.p_name.value = "SolidityTests";
dev::test::Options::get().validate();
- solAssert(registerTests(
- master,
- dev::test::Options::get().testPath / "libsolidity",
- "syntaxTests",
- SyntaxTest::create
- ) > 0, "no syntax tests found");
- solAssert(registerTests(
- master,
- dev::test::Options::get().testPath / "libsolidity",
- "ASTJSON",
- ASTJSONTest::create
- ) > 0, "no JSON AST tests found");
- solAssert(registerTests(
- master,
- dev::test::Options::get().testPath / "libyul",
- "yulOptimizerTests",
- yul::test::YulOptimizerTest::create
- ) > 0, "no Yul Optimizer tests found");
- solAssert(registerTests(
- master,
- dev::test::Options::get().testPath / "libyul",
- "objectCompiler",
- yul::test::ObjectCompilerTest::create
- ) > 0, "no Yul Object compiler tests found");
- if (!dev::test::Options::get().disableSMT)
+
+ // Include the interactive tests in the automatic tests as well
+ for (auto const& ts: g_interactiveTestsuites)
{
- solAssert(registerTests(
- master,
- dev::test::Options::get().testPath / "libsolidity",
- "smtCheckerTests",
- SyntaxTest::create
- ) > 0, "no SMT checker tests found");
+ auto const& options = dev::test::Options::get();
+
+ if (ts.smt && options.disableSMT)
+ continue;
+
+ if (ts.ipc && options.disableIPC)
+ continue;
solAssert(registerTests(
master,
- dev::test::Options::get().testPath / "libsolidity",
- "smtCheckerTestsJSON",
- SMTCheckerTest::create
- ) > 0, "no SMT checker JSON tests found");
+ options.testPath / ts.path,
+ ts.subpath,
+ ts.testCaseCreator
+ ) > 0, std::string("no ") + ts.title + " tests found");
}
+
if (dev::test::Options::get().disableIPC)
{
for (auto suite: {
@@ -188,6 +165,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
})
removeTestSuite(suite);
}
+
if (dev::test::Options::get().disableSMT)
removeTestSuite("SMTChecker");
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol
index 441cf81e..295cf4ea 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/313_fixed_type_size_capabilities.sol
@@ -10,4 +10,5 @@ contract test {
}
}
// ----
-// Warning: (20-707): Function state mutability can be restricted to pure
+// TypeError: (153-250): Type rational_const 9208...(70 digits omitted)...7637 / 1000...(71 digits omitted)...0000 is not implicitly convertible to expected type ufixed256x77, but it can be explicitly converted.
+// TypeError: (470-566): Type rational_const -933...(70 digits omitted)...0123 / 1000...(70 digits omitted)...0000 is not implicitly convertible to expected type fixed256x76, but it can be explicitly converted.
diff --git a/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol b/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol
new file mode 100644
index 00000000..ca50e03b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/rational_number_literal_to_fixed_implicit.sol
@@ -0,0 +1,15 @@
+contract C {
+ function literalToUFixed() public pure {
+ ufixed8x2 a = 0.10;
+ ufixed8x2 b = 0.00;
+ ufixed8x2 c = 2.55;
+ a; b; c;
+ }
+ function literalToFixed() public pure {
+ fixed8x1 a = 0.1;
+ fixed8x1 b = 12.7;
+ fixed8x1 c = -12.8;
+ a; b; c;
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol b/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol
index 66bd9a8e..f86ffcdd 100644
--- a/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol
+++ b/test/libsolidity/syntaxTests/types/too_small_negative_numbers.sol
@@ -2,3 +2,4 @@ contract C {
fixed8x80 a = -1e-100;
}
// ----
+// TypeError: (29-36): Type rational_const -1 / 1000...(93 digits omitted)...0000 is not implicitly convertible to expected type fixed8x80, but it can be explicitly converted.
diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp
index 13585887..e5578045 100644
--- a/test/tools/isoltest.cpp
+++ b/test/tools/isoltest.cpp
@@ -19,11 +19,7 @@
#include <test/Common.h>
#include <test/libsolidity/AnalysisFramework.h>
-#include <test/libsolidity/SyntaxTest.h>
-#include <test/libsolidity/ASTJSONTest.h>
-#include <test/libsolidity/SMTCheckerJSONTest.h>
-#include <test/libyul/YulOptimizerTest.h>
-#include <test/libyul/ObjectCompilerTest.h>
+#include <test/InteractiveTests.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
@@ -380,59 +376,13 @@ Allowed options)",
TestStats global_stats{0, 0};
// Actually run the tests.
- // If you add new tests here, you also have to add them in boostTest.cpp
- if (auto stats = runTestSuite("Syntax", testPath / "libsolidity", "syntaxTests", SyntaxTest::create, formatted))
- global_stats += *stats;
- else
- return 1;
-
- if (auto stats = runTestSuite("JSON AST", testPath / "libsolidity", "ASTJSON", ASTJSONTest::create, formatted))
- global_stats += *stats;
- else
- return 1;
-
- if (auto stats = runTestSuite(
- "Yul Optimizer",
- testPath / "libyul",
- "yulOptimizerTests",
- yul::test::YulOptimizerTest::create,
- formatted
- ))
- global_stats += *stats;
- else
- return 1;
-
- if (auto stats = runTestSuite(
- "Yul Object Compiler",
- testPath / "libyul",
- "objectCompiler",
- yul::test::ObjectCompilerTest::create,
- formatted
- ))
- global_stats += *stats;
- else
- return 1;
-
- if (!disableSMT)
+ // Interactive tests are added in InteractiveTests.h
+ for (auto const& ts: g_interactiveTestsuites)
{
- if (auto stats = runTestSuite(
- "SMT Checker",
- testPath / "libsolidity",
- "smtCheckerTests",
- SyntaxTest::create,
- formatted
- ))
- global_stats += *stats;
- else
- return 1;
+ if (ts.smt && disableSMT)
+ continue;
- if (auto stats = runTestSuite(
- "SMT Checker JSON",
- testPath / "libsolidity",
- "smtCheckerTestsJSON",
- SMTCheckerTest::create,
- formatted
- ))
+ if (auto stats = runTestSuite(ts.title, testPath / ts.path, ts.subpath, ts.testCaseCreator, formatted))
global_stats += *stats;
else
return 1;