diff options
-rw-r--r-- | libdevcore/Result.h | 66 | ||||
-rw-r--r-- | libsolidity/analysis/ConstantEvaluator.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 96 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 109 | ||||
-rw-r--r-- | libyul/AsmAnalysis.cpp | 4 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.cpp | 24 | ||||
-rw-r--r-- | libyul/optimiser/FullInliner.h | 12 | ||||
-rwxr-xr-x | scripts/docker_deploy_manual.sh | 6 | ||||
-rw-r--r-- | test/tools/yulopti.cpp | 2 |
9 files changed, 204 insertions, 117 deletions
diff --git a/libdevcore/Result.h b/libdevcore/Result.h new file mode 100644 index 00000000..4f7a063b --- /dev/null +++ b/libdevcore/Result.h @@ -0,0 +1,66 @@ +/* + 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 <string> + +namespace dev +{ + +/// Simple generic result that holds a value and an optional error message. +/// Results can be implicitly converted to and created from the type of +/// the value they hold. The class is mainly designed for a result type of +/// bool or pointer type. The idea is that the default constructed value of +/// the result type is interpreted as an error value. +/// +/// Result<bool> check() +/// { +/// if (false) +/// return Result<bool>("Error message.") +/// return true; +/// } +/// + +template <class ResultType> +class Result +{ +public: + Result(ResultType _value): Result(_value, std::string{}) {} + Result(std::string _message): Result(ResultType{}, std::move(_message)) {} + + /// @{ + /// @name Wrapper functions + /// Wrapper functions that provide implicit conversions to and explicit retrieval of + /// the value this result holds. + operator ResultType const&() const { return m_value; } + ResultType const& get() const { return m_value; } + /// @} + + /// @returns the error message (can be empty). + std::string const& message() const { return m_message; } + +private: + explicit Result(ResultType _value, std::string _message): + m_value(std::move(_value)), + m_message(std::move(_message)) + {} + + ResultType m_value; + std::string m_message; +}; + +} diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 9d041ce5..26d9584b 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -41,7 +41,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation) auto right = type(_operation.rightExpression()); if (left && right) { - auto commonType = left->binaryOperatorResult(_operation.getOperator(), right); + TypePointer commonType = left->binaryOperatorResult(_operation.getOperator(), right); if (!commonType) m_errorReporter.fatalTypeError( _operation.location(), diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 6cadb5f3..c6b4211a 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -466,7 +466,7 @@ string AddressType::richIdentifier() const return "t_address"; } -bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const +BoolResult AddressType::isImplicitlyConvertibleTo(Type const& _other) const { if (_other.category() != category()) return false; @@ -475,7 +475,7 @@ bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const return other.m_stateMutability <= m_stateMutability; } -bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const { if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo)) return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable(); @@ -504,13 +504,13 @@ u256 AddressType::literalValue(Literal const* _literal) const return u256(_literal->valueWithoutUnderscores()); } -TypePointer AddressType::unaryOperatorResult(Token _operator) const +TypeResult AddressType::unaryOperatorResult(Token _operator) const { return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); } -TypePointer AddressType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult AddressType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { // Addresses can only be compared. if (!TokenTraits::isCompareOp(_operator)) @@ -576,7 +576,7 @@ string IntegerType::richIdentifier() const return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits()); } -bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (_convertTo.category() == category()) { @@ -597,7 +597,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } -bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const { return _convertTo.category() == category() || _convertTo.category() == Category::Address || @@ -607,18 +607,18 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const _convertTo.category() == Category::FixedPoint; } -TypePointer IntegerType::unaryOperatorResult(Token _operator) const +TypeResult IntegerType::unaryOperatorResult(Token _operator) const { // "delete" is ok for all integer types if (_operator == Token::Delete) - return make_shared<TupleType>(); + return TypeResult{make_shared<TupleType>()}; // we allow +, -, ++ and -- else if (_operator == Token::Add || _operator == Token::Sub || _operator == Token::Inc || _operator == Token::Dec || _operator == Token::BitNot) - return shared_from_this(); + return TypeResult{shared_from_this()}; else - return TypePointer(); + return TypeResult{""}; } bool IntegerType::operator==(Type const& _other) const @@ -651,7 +651,7 @@ bigint IntegerType::maxValue() const return (bigint(1) << m_bits) - 1; } -TypePointer IntegerType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult IntegerType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { if ( _other->category() != Category::RationalNumber && @@ -704,7 +704,7 @@ string FixedPointType::richIdentifier() const return "t_" + string(isSigned() ? "" : "u") + "fixed" + to_string(m_totalBits) + "x" + to_string(m_fractionalDigits); } -bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (_convertTo.category() == category()) { @@ -717,18 +717,18 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } -bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const { return _convertTo.category() == category() || _convertTo.category() == Category::Integer; } -TypePointer FixedPointType::unaryOperatorResult(Token _operator) const +TypeResult FixedPointType::unaryOperatorResult(Token _operator) const { switch(_operator) { case Token::Delete: // "delete" is ok for all fixed types - return make_shared<TupleType>(); + return TypeResult(make_shared<TupleType>()); case Token::Add: case Token::Sub: case Token::Inc: @@ -771,7 +771,7 @@ bigint FixedPointType::minIntegerValue() const return bigint(0); } -TypePointer FixedPointType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult FixedPointType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { auto commonType = Type::commonType(shared_from_this(), _other); @@ -957,7 +957,7 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal return make_tuple(true, value); } -bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const { switch (_convertTo.category()) { @@ -995,7 +995,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const } } -bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const { if (isImplicitlyConvertibleTo(_convertTo)) return true; @@ -1008,7 +1008,7 @@ bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const return false; } -TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const +TypeResult RationalNumberType::unaryOperatorResult(Token _operator) const { rational value; switch (_operator) @@ -1029,10 +1029,10 @@ TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const default: return TypePointer(); } - return make_shared<RationalNumberType>(value); + return TypeResult(make_shared<RationalNumberType>(value)); } -TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult RationalNumberType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint) { @@ -1214,7 +1214,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token _operator, TypePointe if (value.numerator() != 0 && max(mostSignificantBit(abs(value.numerator())), mostSignificantBit(abs(value.denominator()))) > 4096) return TypePointer(); - return make_shared<RationalNumberType>(value); + return TypeResult(make_shared<RationalNumberType>(value)); } } @@ -1354,7 +1354,7 @@ StringLiteralType::StringLiteralType(Literal const& _literal): { } -bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo)) return size_t(fixedBytes->numBytes()) >= m_value.size(); @@ -1409,7 +1409,7 @@ FixedBytesType::FixedBytesType(unsigned _bytes): m_bytes(_bytes) ); } -bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (_convertTo.category() != category()) return false; @@ -1417,7 +1417,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const return convertTo.m_bytes >= m_bytes; } -bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const { return (_convertTo.category() == Category::Integer && numBytes() * 8 == dynamic_cast<IntegerType const&>(_convertTo).numBits()) || (_convertTo.category() == Category::Address && numBytes() == 20) || @@ -1425,18 +1425,18 @@ bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const _convertTo.category() == category(); } -TypePointer FixedBytesType::unaryOperatorResult(Token _operator) const +TypeResult FixedBytesType::unaryOperatorResult(Token _operator) const { // "delete" and "~" is okay for FixedBytesType if (_operator == Token::Delete) - return make_shared<TupleType>(); + return TypeResult(make_shared<TupleType>()); else if (_operator == Token::BitNot) return shared_from_this(); return TypePointer(); } -TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { if (TokenTraits::isShiftOp(_operator)) { @@ -1452,7 +1452,7 @@ TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer co // FixedBytes can be compared and have bitwise operators applied to them if (TokenTraits::isCompareOp(_operator) || TokenTraits::isBitOp(_operator)) - return commonType; + return TypeResult(commonType); return TypePointer(); } @@ -1486,14 +1486,14 @@ u256 BoolType::literalValue(Literal const* _literal) const solAssert(false, "Bool type constructed from non-boolean literal."); } -TypePointer BoolType::unaryOperatorResult(Token _operator) const +TypeResult BoolType::unaryOperatorResult(Token _operator) const { if (_operator == Token::Delete) - return make_shared<TupleType>(); + return TypeResult(make_shared<TupleType>()); return (_operator == Token::Not) ? shared_from_this() : TypePointer(); } -TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult BoolType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { if (category() != _other->category()) return TypePointer(); @@ -1503,7 +1503,7 @@ TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _ return TypePointer(); } -bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (*this == _convertTo) return true; @@ -1520,7 +1520,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } -bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const { if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo)) return isPayable() || (addressType->stateMutability() < StateMutability::Payable); @@ -1533,14 +1533,14 @@ bool ContractType::isPayable() const return fallbackFunction && fallbackFunction->isPayable(); } -TypePointer ContractType::unaryOperatorResult(Token _operator) const +TypeResult ContractType::unaryOperatorResult(Token _operator) const { if (isSuper()) return TypePointer{}; return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); } -TypePointer ReferenceType::unaryOperatorResult(Token _operator) const +TypeResult ReferenceType::unaryOperatorResult(Token _operator) const { if (_operator != Token::Delete) return TypePointer(); @@ -1551,7 +1551,7 @@ TypePointer ReferenceType::unaryOperatorResult(Token _operator) const case DataLocation::CallData: return TypePointer(); case DataLocation::Memory: - return make_shared<TupleType>(); + return TypeResult(make_shared<TupleType>()); case DataLocation::Storage: return m_isPointer ? TypePointer() : make_shared<TupleType>(); } @@ -1605,7 +1605,7 @@ string ReferenceType::identifierLocationSuffix() const return id; } -bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const +BoolResult ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const { if (_convertTo.category() != category()) return false; @@ -1645,7 +1645,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const } } -bool ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const +BoolResult ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const { if (isImplicitlyConvertibleTo(_convertTo)) return true; @@ -2006,7 +2006,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar return variablesAndOffsets; } -bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const +BoolResult StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const { if (_convertTo.category() != category()) return false; @@ -2249,7 +2249,7 @@ bool StructType::recursive() const return *m_recursive; } -TypePointer EnumType::unaryOperatorResult(Token _operator) const +TypeResult EnumType::unaryOperatorResult(Token _operator) const { return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); } @@ -2291,7 +2291,7 @@ size_t EnumType::numberOfMembers() const return m_enum.members().size(); }; -bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const { return _convertTo == *this || _convertTo.category() == Category::Integer; } @@ -2308,7 +2308,7 @@ unsigned EnumType::memberValue(ASTString const& _member) const solAssert(false, "Requested unknown enum value " + _member); } -bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const +BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const { if (auto tupleType = dynamic_cast<TupleType const*>(&_other)) { @@ -2648,14 +2648,14 @@ bool FunctionType::operator==(Type const& _other) const return true; } -bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const { if (m_kind == Kind::External && _convertTo == AddressType::address()) return true; return _convertTo.category() == category(); } -bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const +BoolResult FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (_convertTo.category() != category()) return false; @@ -2680,14 +2680,14 @@ bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const return true; } -TypePointer FunctionType::unaryOperatorResult(Token _operator) const +TypeResult FunctionType::unaryOperatorResult(Token _operator) const { if (_operator == Token::Delete) - return make_shared<TupleType>(); + return TypeResult(make_shared<TupleType>()); return TypePointer(); } -TypePointer FunctionType::binaryOperatorResult(Token _operator, TypePointer const& _other) const +TypeResult FunctionType::binaryOperatorResult(Token _operator, TypePointer const& _other) const { if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual)) return TypePointer(); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 0f0548d3..39157abe 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -29,6 +29,7 @@ #include <libdevcore/Common.h> #include <libdevcore/CommonIO.h> +#include <libdevcore/Result.h> #include <boost/noncopyable.hpp> #include <boost/rational.hpp> @@ -50,6 +51,8 @@ using TypePointer = std::shared_ptr<Type const>; using FunctionTypePointer = std::shared_ptr<FunctionType const>; using TypePointers = std::vector<TypePointer>; using rational = boost::rational<dev::bigint>; +using TypeResult = Result<TypePointer>; +using BoolResult = Result<bool>; inline rational makeRational(bigint const& _numerator, bigint const& _denominator) { @@ -63,6 +66,7 @@ inline rational makeRational(bigint const& _numerator, bigint const& _denominato enum class DataLocation { Storage, CallData, Memory }; + /** * Helper class to compute storage offsets of members of structs and contracts. */ @@ -189,19 +193,19 @@ public: /// @returns an escaped identifier (will not contain any parenthesis or commas) static std::string escapeIdentifier(std::string const& _identifier); - virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } - virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const + virtual BoolResult isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } + virtual BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const { return isImplicitlyConvertibleTo(_convertTo); } /// @returns the resulting type of applying the given unary operator or an empty pointer if /// this is not possible. /// The default implementation does not allow any unary operator. - virtual TypePointer unaryOperatorResult(Token) const { return TypePointer(); } + virtual TypeResult unaryOperatorResult(Token) const { return TypePointer(); } /// @returns the resulting type of applying the given binary operator or an empty pointer if /// this is not possible. /// The default implementation allows comparison operators if a common type exists - virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const + virtual TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const { return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer(); } @@ -336,10 +340,10 @@ public: explicit AddressType(StateMutability _stateMutability); std::string richIdentifier() const override; - bool isImplicitlyConvertibleTo(Type const& _other) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; bool operator==(Type const& _other) const override; @@ -381,10 +385,10 @@ public: explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned); std::string richIdentifier() const override; - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; bool operator==(Type const& _other) const override; @@ -423,10 +427,10 @@ public: explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned); std::string richIdentifier() const override; - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; bool operator==(Type const& _other) const override; @@ -476,11 +480,10 @@ public: explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()): m_value(_value), m_compatibleBytesType(_compatibleBytesType) {} - - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; @@ -536,8 +539,8 @@ public: explicit StringLiteralType(Literal const& _literal); - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer binaryOperatorResult(Token, TypePointer const&) const override + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } @@ -570,12 +573,12 @@ public: explicit FixedBytesType(unsigned _bytes); - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; } unsigned storageBytes() const override { return m_bytes; } @@ -601,8 +604,8 @@ public: BoolType() {} Category category() const override { return Category::Bool; } std::string richIdentifier() const override { return "t_bool"; } - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override; unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; } unsigned storageBytes() const override { return 1; } @@ -624,8 +627,8 @@ public: explicit ReferenceType(DataLocation _location): m_location(_location) {} DataLocation location() const { return m_location; } - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token, TypePointer const&) const override + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } @@ -702,8 +705,8 @@ public: m_length(_length) {} - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; std::string richIdentifier() const override; bool operator==(const Type& _other) const override; unsigned calldataEncodedSize(bool _padded) const override; @@ -757,10 +760,10 @@ public: explicit ContractType(ContractDefinition const& _contract, bool _super = false): m_contract(_contract), m_super(_super) {} /// Contracts can be implicitly converted only to base contracts. - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; /// Contracts can only be explicitly converted to address types and base contracts. - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; unsigned calldataEncodedSize(bool _padded ) const override @@ -821,7 +824,7 @@ public: Category category() const override { return Category::Struct; } explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage): ReferenceType(_location), m_struct(_struct) {} - bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; + BoolResult isImplicitlyConvertibleTo(const Type& _convertTo) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; unsigned calldataEncodedSize(bool _padded) const override; @@ -876,7 +879,7 @@ class EnumType: public Type public: Category category() const override { return Category::Enum; } explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {} - TypePointer unaryOperatorResult(Token _operator) const override; + TypeResult unaryOperatorResult(Token _operator) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; unsigned calldataEncodedSize(bool _padded) const override @@ -889,7 +892,7 @@ public: std::string canonicalName() const override; bool isValueType() const override { return true; } - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; TypePointer encodingType() const override { return std::make_shared<IntegerType>(8 * int(storageBytes())); @@ -917,10 +920,10 @@ class TupleType: public Type public: Category category() const override { return Category::Tuple; } explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {} - bool isImplicitlyConvertibleTo(Type const& _other) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _other) const override; std::string richIdentifier() const override; bool operator==(Type const& _other) const override; - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } std::string toString(bool) const override; bool canBeStored() const override { return false; } u256 storageSize() const override; @@ -1065,10 +1068,10 @@ public: std::string richIdentifier() const override; bool operator==(Type const& _other) const override; - bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - TypePointer unaryOperatorResult(Token _operator) const override; - TypePointer binaryOperatorResult(Token, TypePointer const&) const override; + BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override; + BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; + TypeResult unaryOperatorResult(Token _operator) const override; + TypeResult binaryOperatorResult(Token, TypePointer const&) const override; std::string canonicalName() const override; std::string toString(bool _short) const override; unsigned calldataEncodedSize(bool _padded) const override; @@ -1197,7 +1200,7 @@ public: std::string toString(bool _short) const override; std::string canonicalName() const override; bool canLiveOutsideStorage() const override { return false; } - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } TypePointer encodingType() const override { return std::make_shared<IntegerType>(256); @@ -1230,7 +1233,7 @@ public: explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} TypePointer const& actualType() const { return m_actualType; } - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } @@ -1255,7 +1258,7 @@ public: Category category() const override { return Category::Modifier; } explicit ModifierType(ModifierDefinition const& _modifier); - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } bool canBeStored() const override { return false; } u256 storageSize() const override; bool canLiveOutsideStorage() const override { return false; } @@ -1281,7 +1284,7 @@ public: explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {} - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } std::string richIdentifier() const override; bool operator==(Type const& _other) const override; bool canBeStored() const override { return false; } @@ -1308,7 +1311,7 @@ public: explicit MagicType(Kind _kind): m_kind(_kind) {} - TypePointer binaryOperatorResult(Token, TypePointer const&) const override + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } @@ -1339,9 +1342,9 @@ public: Category category() const override { return Category::InaccessibleDynamic; } std::string richIdentifier() const override { return "t_inaccessible"; } - bool isImplicitlyConvertibleTo(Type const&) const override { return false; } - bool isExplicitlyConvertibleTo(Type const&) const override { return false; } - TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } + BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; } + BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; } + TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; } bool canBeStored() const override { return false; } bool canLiveOutsideStorage() const override { return false; } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 3cbed9c7..1be1cf1a 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -629,7 +629,9 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST) { - solAssert(m_dialect.flavour == AsmFlavour::Loose, ""); + if (m_dialect.flavour != AsmFlavour::Loose) + solAssert(m_errorTypeForLoose && *m_errorTypeForLoose != Error::Type::Warning, ""); + m_errorReporter.error( m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning, _location, diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 8ae26fbb..f69f7cdd 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -94,8 +94,11 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) if (_funCall.functionName.name == _callSite) return false; - FunctionDefinition& calledFunction = function(_funCall.functionName.name); - if (m_alwaysInline.count(calledFunction.name)) + FunctionDefinition* calledFunction = function(_funCall.functionName.name); + if (!calledFunction) + return false; + + if (m_alwaysInline.count(calledFunction->name)) return true; // Constant arguments might provide a means for further optimization, so they cause a bonus. @@ -110,7 +113,7 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite) break; } - size_t size = m_functionSizes.at(calledFunction.name); + size_t size = m_functionSizes.at(calledFunction->name); return (size < 10 || (constantArg && size < 50)); } @@ -149,12 +152,13 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC vector<Statement> newStatements; map<YulString, YulString> variableReplacements; - FunctionDefinition& function = m_driver.function(_funCall.functionName.name); + FunctionDefinition* function = m_driver.function(_funCall.functionName.name); + assertThrow(!!function, OptimizerException, "Attempt to inline invalid function."); // helper function to create a new variable that is supposed to model // an existing variable. auto newVariable = [&](TypedName const& _existingVariable, Expression* _value) { - YulString newName = m_nameDispenser.newName(_existingVariable.name, function.name); + YulString newName = m_nameDispenser.newName(_existingVariable.name, function->name); variableReplacements[_existingVariable.name] = newName; VariableDeclaration varDecl{_funCall.location, {{_funCall.location, newName, _existingVariable.type}}, {}}; if (_value) @@ -163,11 +167,11 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC }; for (size_t i = 0; i < _funCall.arguments.size(); ++i) - newVariable(function.parameters[i], &_funCall.arguments[i]); - for (auto const& var: function.returnVariables) + newVariable(function->parameters[i], &_funCall.arguments[i]); + for (auto const& var: function->returnVariables) newVariable(var, nullptr); - Statement newBody = BodyCopier(m_nameDispenser, function.name, variableReplacements)(function.body); + Statement newBody = BodyCopier(m_nameDispenser, function->name, variableReplacements)(function->body); newStatements += std::move(boost::get<Block>(newBody).statements); boost::apply_visitor(GenericFallbackVisitor<Assignment, VariableDeclaration>{ @@ -179,7 +183,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC {_assignment.variableNames[i]}, make_shared<Expression>(Identifier{ _assignment.location, - variableReplacements.at(function.returnVariables[i].name) + variableReplacements.at(function->returnVariables[i].name) }) }); }, @@ -191,7 +195,7 @@ vector<Statement> InlineModifier::performInline(Statement& _statement, FunctionC {std::move(_varDecl.variables[i])}, make_shared<Expression>(Identifier{ _varDecl.location, - variableReplacements.at(function.returnVariables[i].name) + variableReplacements.at(function->returnVariables[i].name) }) }); } diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h index a8fe76c6..8f6211c8 100644 --- a/libyul/optimiser/FullInliner.h +++ b/libyul/optimiser/FullInliner.h @@ -63,8 +63,8 @@ class NameCollector; * code of f, with replacements: a -> f_a, b -> f_b, c -> f_c * let z := f_c * - * Prerequisites: Disambiguator, Function Hoister - * More efficient if run after: Expression Splitter + * Prerequisites: Disambiguator + * More efficient if run after: Function Hoister, Expression Splitter */ class FullInliner: public ASTModifier { @@ -77,7 +77,13 @@ public: /// @param _callSite the name of the function in which the function call is located. bool shallInline(FunctionCall const& _funCall, YulString _callSite); - FunctionDefinition& function(YulString _name) { return *m_functions.at(_name); } + FunctionDefinition* function(YulString _name) + { + auto it = m_functions.find(_name); + if (it != m_functions.end()) + return it->second; + return nullptr; + } private: void updateCodeSize(FunctionDefinition& fun); diff --git a/scripts/docker_deploy_manual.sh b/scripts/docker_deploy_manual.sh index 0393d22d..30dd267c 100755 --- a/scripts/docker_deploy_manual.sh +++ b/scripts/docker_deploy_manual.sh @@ -37,6 +37,12 @@ tag_and_push() rm -rf .git docker build -t "$image":build -f scripts/Dockerfile . tmp_container=$(docker create "$image":build sh) + +# Alpine image +mkdir -p upload +docker cp ${tmp_container}:/usr/bin/solc upload/solc-static-linux +docker build -t "$image":build-alpine -f scripts/Dockerfile_alpine . + if [ "$branch" = "develop" ] then tag_and_push build nightly diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index e867f049..d0643d73 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -94,7 +94,7 @@ public: *m_analysisInfo, errorReporter, EVMVersion::byzantium(), - boost::none, + langutil::Error::Type::SyntaxError, Dialect::strictAssemblyForEVM() ); if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) |