diff options
-rw-r--r-- | Changelog.md | 2 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 12 | ||||
-rw-r--r-- | libsolidity/analysis/ConstantEvaluator.cpp | 23 | ||||
-rw-r--r-- | libsolidity/formal/SMTLib2Interface.cpp | 9 | ||||
-rw-r--r-- | libsolidity/formal/SMTLib2Interface.h | 8 | ||||
-rw-r--r-- | libsolidity/interface/SourceReferenceFormatter.cpp | 15 | ||||
-rw-r--r-- | test/RPCSession.cpp | 19 | ||||
-rw-r--r-- | test/RPCSession.h | 1 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 6 |
9 files changed, 75 insertions, 20 deletions
diff --git a/Changelog.md b/Changelog.md index 68b9973f..45521f3e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Features: * Syntax Checker: Turn the usage of ``callcode`` into an error as experimental 0.5.0 feature. + * Type Checker: More detailed errors for invalid array lengths (such as division by zero). Bugfixes: @@ -18,6 +19,7 @@ Features: * Type Checker: Do not add members of ``address`` to contracts as experimental 0.5.0 feature. * Type Checker: Force interface functions to be external as experimental 0.5.0 feature. * Type Checker: Require ``storage`` or ``memory`` keyword for local variables as experimental 0.5.0 feature. + * Compiler Interface: Better formatted error message for long source snippets Bugfixes: * Code Generator: Allocate one byte per memory byte array element instead of 32. diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 139c8a42..59ab7962 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -221,8 +221,7 @@ activate themselves. // absolute unix timestamps (seconds since 1970-01-01) // or time periods in seconds. address public beneficiary; - uint public auctionStart; - uint public biddingTime; + uint public auctionEnd; // Current state of the auction. address public highestBidder; @@ -251,8 +250,7 @@ activate themselves. address _beneficiary ) { beneficiary = _beneficiary; - auctionStart = now; - biddingTime = _biddingTime; + auctionEnd = now + _biddingTime; } /// Bid on the auction with the value sent @@ -268,7 +266,7 @@ activate themselves. // Revert the call if the bidding // period is over. - require(now <= (auctionStart + biddingTime)); + require(now <= auctionEnd); // If the bid is not higher, send the // money back. @@ -322,7 +320,7 @@ activate themselves. // external contracts. // 1. Conditions - require(now >= (auctionStart + biddingTime)); // auction did not yet end + require(now >= auctionEnd); // auction did not yet end require(!ended); // this function has already been called // 2. Effects @@ -382,7 +380,6 @@ high or low invalid bids. } address public beneficiary; - uint public auctionStart; uint public biddingEnd; uint public revealEnd; bool public ended; @@ -410,7 +407,6 @@ high or low invalid bids. address _beneficiary ) { beneficiary = _beneficiary; - auctionStart = now; biddingEnd = now + _biddingTime; revealEnd = biddingEnd + _revealTime; } diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 6636ad97..bc3b7cf1 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -28,6 +28,7 @@ using namespace std; using namespace dev; using namespace dev::solidity; +/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation) void ConstantEvaluator::endVisit(UnaryOperation const& _operation) { TypePointer const& subType = _operation.subExpression().annotation().type; @@ -37,6 +38,7 @@ void ConstantEvaluator::endVisit(UnaryOperation const& _operation) _operation.annotation().type = t; } +/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation) void ConstantEvaluator::endVisit(BinaryOperation const& _operation) { TypePointer const& leftType = _operation.leftExpression().annotation().type; @@ -46,9 +48,24 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation) if (!dynamic_cast<RationalNumberType const*>(rightType.get())) m_errorReporter.fatalTypeError(_operation.rightExpression().location(), "Invalid constant expression."); TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType); - if (Token::isCompareOp(_operation.getOperator())) - commonType = make_shared<BoolType>(); - _operation.annotation().type = commonType; + if (!commonType) + { + m_errorReporter.typeError( + _operation.location(), + "Operator " + + string(Token::toString(_operation.getOperator())) + + " not compatible with types " + + leftType->toString() + + " and " + + rightType->toString() + ); + commonType = leftType; + } + _operation.annotation().commonType = commonType; + _operation.annotation().type = + Token::isCompareOp(_operation.getOperator()) ? + make_shared<BoolType>() : + commonType; } void ConstantEvaluator::endVisit(Literal const& _literal) diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp index cbd766fb..c627057a 100644 --- a/libsolidity/formal/SMTLib2Interface.cpp +++ b/libsolidity/formal/SMTLib2Interface.cpp @@ -64,6 +64,8 @@ void SMTLib2Interface::pop() Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codomain) { + solAssert(!m_variables.count(_name), ""); + m_variables[_name] = SMTVariableType::Function; write( "(declare-fun |" + _name + @@ -78,12 +80,16 @@ Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codom Expression SMTLib2Interface::newInteger(string _name) { + solAssert(!m_variables.count(_name), ""); + m_variables[_name] = SMTVariableType::Integer; write("(declare-const |" + _name + "| Int)"); return SolverInterface::newInteger(move(_name)); } Expression SMTLib2Interface::newBool(string _name) { + solAssert(!m_variables.count(_name), ""); + m_variables[_name] = SMTVariableType::Bool; write("(declare-const |" + _name + "| Bool)"); return SolverInterface::newBool(std::move(_name)); } @@ -145,7 +151,8 @@ string SMTLib2Interface::checkSatAndGetValuesCommand(vector<Expression> const& _ for (size_t i = 0; i < _expressionsToEvaluate.size(); i++) { auto const& e = _expressionsToEvaluate.at(i); - // TODO they don't have to be ints... + solAssert(m_variables.count(e.name), ""); + solAssert(m_variables[e.name] == SMTVariableType::Integer, ""); command += "(declare-const |EVALEXPR_" + to_string(i) + "| Int)\n"; command += "(assert (= |EVALEXPR_" + to_string(i) + "| " + toSExpr(e) + "))\n"; } diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h index 63188acd..e827449f 100644 --- a/libsolidity/formal/SMTLib2Interface.h +++ b/libsolidity/formal/SMTLib2Interface.h @@ -68,6 +68,14 @@ private: ReadCallback::Callback m_queryCallback; std::vector<std::string> m_accumulatedOutput; + + enum class SMTVariableType { + Function, + Integer, + Bool + }; + + std::map<std::string,SMTVariableType> m_variables; }; } diff --git a/libsolidity/interface/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp index 62d22999..aeafaf2d 100644 --- a/libsolidity/interface/SourceReferenceFormatter.cpp +++ b/libsolidity/interface/SourceReferenceFormatter.cpp @@ -49,6 +49,21 @@ void SourceReferenceFormatter::printSourceLocation( if (startLine == endLine) { string line = scanner.lineAtPosition(_location->start); + + int locationLength = endColumn - startColumn; + if (locationLength > 150) + { + line = line.substr(0, startColumn + 35) + " ... " + line.substr(endColumn - 35); + endColumn = startColumn + 75; + locationLength = 75; + } + if (line.length() > 150) + { + line = " ... " + line.substr(startColumn, locationLength) + " ... "; + startColumn = 5; + endColumn = startColumn + locationLength; + } + _stream << line << endl; for_each( line.cbegin(), diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp index 634954a3..c06c3997 100644 --- a/test/RPCSession.cpp +++ b/test/RPCSession.cpp @@ -339,22 +339,25 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const& return result["result"]; } +string const& RPCSession::accountCreate() +{ + m_accounts.push_back(personal_newAccount("")); + personal_unlockAccount(m_accounts.back(), "", 100000); + return m_accounts.back(); +} + string const& RPCSession::accountCreateIfNotExists(size_t _id) { - if (_id >= m_accounts.size()) - { - m_accounts.push_back(personal_newAccount("")); - personal_unlockAccount(m_accounts.back(), "", 100000); - } + while ((_id + 1) > m_accounts.size()) + accountCreate(); return m_accounts[_id]; } RPCSession::RPCSession(const string& _path): m_ipcSocket(_path) { - string account = personal_newAccount(""); - personal_unlockAccount(account, "", 100000); - m_accounts.push_back(account); + accountCreate(); + // This will pre-fund the accounts create prior. test_setChainParams(m_accounts); } diff --git a/test/RPCSession.h b/test/RPCSession.h index eae6a09c..63f1dd21 100644 --- a/test/RPCSession.h +++ b/test/RPCSession.h @@ -121,6 +121,7 @@ public: Json::Value rpcCall(std::string const& _methodName, std::vector<std::string> const& _args = std::vector<std::string>(), bool _canFail = false); std::string const& account(size_t _id) const { return m_accounts.at(_id); } + std::string const& accountCreate(); std::string const& accountCreateIfNotExists(size_t _id); private: diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 9b5ea349..e5990e9b 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -7247,6 +7247,12 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression) } )"; CHECK_ERROR(text, TypeError, "Invalid literal value."); + text = R"( + contract C { + uint[3/0] ids; + } + )"; + CHECK_ERROR(text, TypeError, "Operator / not compatible with types int_const 3 and int_const 0"); } BOOST_AUTO_TEST_CASE(no_address_members_on_contract) |