Merge pull request #4098 from ethereum/typedResults

Introduce Result<T> for type checker functions
This commit is contained in:
chriseth 2018-12-05 14:10:30 +01:00 committed by GitHub
commit 57eb68a8df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 171 additions and 102 deletions

66
libdevcore/Result.h Normal file
View File

@ -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;
};
}

View File

@ -41,7 +41,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
auto right = type(_operation.rightExpression()); auto right = type(_operation.rightExpression());
if (left && right) if (left && right)
{ {
auto commonType = left->binaryOperatorResult(_operation.getOperator(), right); TypePointer commonType = left->binaryOperatorResult(_operation.getOperator(), right);
if (!commonType) if (!commonType)
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
_operation.location(), _operation.location(),

View File

@ -466,7 +466,7 @@ string AddressType::richIdentifier() const
return "t_address"; return "t_address";
} }
bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const BoolResult AddressType::isImplicitlyConvertibleTo(Type const& _other) const
{ {
if (_other.category() != category()) if (_other.category() != category())
return false; return false;
@ -475,7 +475,7 @@ bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const
return other.m_stateMutability <= m_stateMutability; 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)) if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable(); return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
@ -504,13 +504,13 @@ u256 AddressType::literalValue(Literal const* _literal) const
return u256(_literal->valueWithoutUnderscores()); return u256(_literal->valueWithoutUnderscores());
} }
TypePointer AddressType::unaryOperatorResult(Token _operator) const TypeResult AddressType::unaryOperatorResult(Token _operator) const
{ {
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); 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. // Addresses can only be compared.
if (!TokenTraits::isCompareOp(_operator)) if (!TokenTraits::isCompareOp(_operator))
@ -576,7 +576,7 @@ string IntegerType::richIdentifier() const
return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits()); 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()) if (_convertTo.category() == category())
{ {
@ -597,7 +597,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false; return false;
} }
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const BoolResult IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return _convertTo.category() == category() || return _convertTo.category() == category() ||
_convertTo.category() == Category::Address || _convertTo.category() == Category::Address ||
@ -607,18 +607,18 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == Category::FixedPoint; _convertTo.category() == Category::FixedPoint;
} }
TypePointer IntegerType::unaryOperatorResult(Token _operator) const TypeResult IntegerType::unaryOperatorResult(Token _operator) const
{ {
// "delete" is ok for all integer types // "delete" is ok for all integer types
if (_operator == Token::Delete) if (_operator == Token::Delete)
return make_shared<TupleType>(); return TypeResult{make_shared<TupleType>()};
// we allow +, -, ++ and -- // we allow +, -, ++ and --
else if (_operator == Token::Add || _operator == Token::Sub || else if (_operator == Token::Add || _operator == Token::Sub ||
_operator == Token::Inc || _operator == Token::Dec || _operator == Token::Inc || _operator == Token::Dec ||
_operator == Token::BitNot) _operator == Token::BitNot)
return shared_from_this(); return TypeResult{shared_from_this()};
else else
return TypePointer(); return TypeResult{""};
} }
bool IntegerType::operator==(Type const& _other) const bool IntegerType::operator==(Type const& _other) const
@ -651,7 +651,7 @@ bigint IntegerType::maxValue() const
return (bigint(1) << m_bits) - 1; 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 ( if (
_other->category() != Category::RationalNumber && _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); 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()) if (_convertTo.category() == category())
{ {
@ -717,18 +717,18 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false; return false;
} }
bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const BoolResult FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return _convertTo.category() == category() || _convertTo.category() == Category::Integer; return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
} }
TypePointer FixedPointType::unaryOperatorResult(Token _operator) const TypeResult FixedPointType::unaryOperatorResult(Token _operator) const
{ {
switch(_operator) switch(_operator)
{ {
case Token::Delete: case Token::Delete:
// "delete" is ok for all fixed types // "delete" is ok for all fixed types
return make_shared<TupleType>(); return TypeResult(make_shared<TupleType>());
case Token::Add: case Token::Add:
case Token::Sub: case Token::Sub:
case Token::Inc: case Token::Inc:
@ -771,7 +771,7 @@ bigint FixedPointType::minIntegerValue() const
return bigint(0); 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); 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); return make_tuple(true, value);
} }
bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const BoolResult RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
switch (_convertTo.category()) 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)) if (isImplicitlyConvertibleTo(_convertTo))
return true; return true;
@ -1008,7 +1008,7 @@ bool RationalNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const
return false; return false;
} }
TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const TypeResult RationalNumberType::unaryOperatorResult(Token _operator) const
{ {
rational value; rational value;
switch (_operator) switch (_operator)
@ -1029,10 +1029,10 @@ TypePointer RationalNumberType::unaryOperatorResult(Token _operator) const
default: default:
return TypePointer(); 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) 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) if (value.numerator() != 0 && max(mostSignificantBit(abs(value.numerator())), mostSignificantBit(abs(value.denominator()))) > 4096)
return TypePointer(); 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)) if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
return size_t(fixedBytes->numBytes()) >= m_value.size(); 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()) if (_convertTo.category() != category())
return false; return false;
@ -1417,7 +1417,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return convertTo.m_bytes >= m_bytes; 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()) || return (_convertTo.category() == Category::Integer && numBytes() * 8 == dynamic_cast<IntegerType const&>(_convertTo).numBits()) ||
(_convertTo.category() == Category::Address && numBytes() == 20) || (_convertTo.category() == Category::Address && numBytes() == 20) ||
@ -1425,18 +1425,18 @@ bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
_convertTo.category() == category(); _convertTo.category() == category();
} }
TypePointer FixedBytesType::unaryOperatorResult(Token _operator) const TypeResult FixedBytesType::unaryOperatorResult(Token _operator) const
{ {
// "delete" and "~" is okay for FixedBytesType // "delete" and "~" is okay for FixedBytesType
if (_operator == Token::Delete) if (_operator == Token::Delete)
return make_shared<TupleType>(); return TypeResult(make_shared<TupleType>());
else if (_operator == Token::BitNot) else if (_operator == Token::BitNot)
return shared_from_this(); return shared_from_this();
return TypePointer(); return TypePointer();
} }
TypePointer FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const TypeResult FixedBytesType::binaryOperatorResult(Token _operator, TypePointer const& _other) const
{ {
if (TokenTraits::isShiftOp(_operator)) 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 // FixedBytes can be compared and have bitwise operators applied to them
if (TokenTraits::isCompareOp(_operator) || TokenTraits::isBitOp(_operator)) if (TokenTraits::isCompareOp(_operator) || TokenTraits::isBitOp(_operator))
return commonType; return TypeResult(commonType);
return TypePointer(); return TypePointer();
} }
@ -1486,14 +1486,14 @@ u256 BoolType::literalValue(Literal const* _literal) const
solAssert(false, "Bool type constructed from non-boolean literal."); 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) if (_operator == Token::Delete)
return make_shared<TupleType>(); return TypeResult(make_shared<TupleType>());
return (_operator == Token::Not) ? shared_from_this() : TypePointer(); 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()) if (category() != _other->category())
return TypePointer(); return TypePointer();
@ -1503,7 +1503,7 @@ TypePointer BoolType::binaryOperatorResult(Token _operator, TypePointer const& _
return TypePointer(); return TypePointer();
} }
bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (*this == _convertTo) if (*this == _convertTo)
return true; return true;
@ -1520,7 +1520,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false; 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)) if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
return isPayable() || (addressType->stateMutability() < StateMutability::Payable); return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
@ -1533,14 +1533,14 @@ bool ContractType::isPayable() const
return fallbackFunction && fallbackFunction->isPayable(); return fallbackFunction && fallbackFunction->isPayable();
} }
TypePointer ContractType::unaryOperatorResult(Token _operator) const TypeResult ContractType::unaryOperatorResult(Token _operator) const
{ {
if (isSuper()) if (isSuper())
return TypePointer{}; return TypePointer{};
return _operator == Token::Delete ? make_shared<TupleType>() : 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) if (_operator != Token::Delete)
return TypePointer(); return TypePointer();
@ -1551,7 +1551,7 @@ TypePointer ReferenceType::unaryOperatorResult(Token _operator) const
case DataLocation::CallData: case DataLocation::CallData:
return TypePointer(); return TypePointer();
case DataLocation::Memory: case DataLocation::Memory:
return make_shared<TupleType>(); return TypeResult(make_shared<TupleType>());
case DataLocation::Storage: case DataLocation::Storage:
return m_isPointer ? TypePointer() : make_shared<TupleType>(); return m_isPointer ? TypePointer() : make_shared<TupleType>();
} }
@ -1605,7 +1605,7 @@ string ReferenceType::identifierLocationSuffix() const
return id; return id;
} }
bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const BoolResult ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{ {
if (_convertTo.category() != category()) if (_convertTo.category() != category())
return false; 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)) if (isImplicitlyConvertibleTo(_convertTo))
return true; return true;
@ -2006,7 +2006,7 @@ vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVar
return variablesAndOffsets; return variablesAndOffsets;
} }
bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const BoolResult StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{ {
if (_convertTo.category() != category()) if (_convertTo.category() != category())
return false; return false;
@ -2249,7 +2249,7 @@ bool StructType::recursive() const
return *m_recursive; return *m_recursive;
} }
TypePointer EnumType::unaryOperatorResult(Token _operator) const TypeResult EnumType::unaryOperatorResult(Token _operator) const
{ {
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
} }
@ -2291,7 +2291,7 @@ size_t EnumType::numberOfMembers() const
return m_enum.members().size(); 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; 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); 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)) if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
{ {
@ -2648,14 +2648,14 @@ bool FunctionType::operator==(Type const& _other) const
return true; return true;
} }
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const BoolResult FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (m_kind == Kind::External && _convertTo == AddressType::address()) if (m_kind == Kind::External && _convertTo == AddressType::address())
return true; return true;
return _convertTo.category() == category(); return _convertTo.category() == category();
} }
bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const BoolResult FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (_convertTo.category() != category()) if (_convertTo.category() != category())
return false; return false;
@ -2680,14 +2680,14 @@ bool FunctionType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return true; return true;
} }
TypePointer FunctionType::unaryOperatorResult(Token _operator) const TypeResult FunctionType::unaryOperatorResult(Token _operator) const
{ {
if (_operator == Token::Delete) if (_operator == Token::Delete)
return make_shared<TupleType>(); return TypeResult(make_shared<TupleType>());
return TypePointer(); 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)) if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual))
return TypePointer(); return TypePointer();

View File

@ -29,6 +29,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Result.h>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <boost/rational.hpp> #include <boost/rational.hpp>
@ -50,6 +51,8 @@ using TypePointer = std::shared_ptr<Type const>;
using FunctionTypePointer = std::shared_ptr<FunctionType const>; using FunctionTypePointer = std::shared_ptr<FunctionType const>;
using TypePointers = std::vector<TypePointer>; using TypePointers = std::vector<TypePointer>;
using rational = boost::rational<dev::bigint>; using rational = boost::rational<dev::bigint>;
using TypeResult = Result<TypePointer>;
using BoolResult = Result<bool>;
inline rational makeRational(bigint const& _numerator, bigint const& _denominator) 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 }; enum class DataLocation { Storage, CallData, Memory };
/** /**
* Helper class to compute storage offsets of members of structs and contracts. * 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) /// @returns an escaped identifier (will not contain any parenthesis or commas)
static std::string escapeIdentifier(std::string const& _identifier); static std::string escapeIdentifier(std::string const& _identifier);
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } virtual BoolResult isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const virtual BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return isImplicitlyConvertibleTo(_convertTo); return isImplicitlyConvertibleTo(_convertTo);
} }
/// @returns the resulting type of applying the given unary operator or an empty pointer if /// @returns the resulting type of applying the given unary operator or an empty pointer if
/// this is not possible. /// this is not possible.
/// The default implementation does not allow any unary operator. /// 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 /// @returns the resulting type of applying the given binary operator or an empty pointer if
/// this is not possible. /// this is not possible.
/// The default implementation allows comparison operators if a common type exists /// 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(); return TokenTraits::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
} }
@ -336,10 +340,10 @@ public:
explicit AddressType(StateMutability _stateMutability); explicit AddressType(StateMutability _stateMutability);
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool isImplicitlyConvertibleTo(Type const& _other) const override; BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
@ -381,10 +385,10 @@ public:
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned); explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type 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); explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
bool operator==(Type 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()): explicit RationalNumberType(rational const& _value, TypePointer const& _compatibleBytesType = TypePointer()):
m_value(_value), m_compatibleBytesType(_compatibleBytesType) m_value(_value), m_compatibleBytesType(_compatibleBytesType)
{} {}
BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
@ -536,8 +539,8 @@ public:
explicit StringLiteralType(Literal const& _literal); explicit StringLiteralType(Literal const& _literal);
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer binaryOperatorResult(Token, TypePointer const&) const override TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{ {
return TypePointer(); return TypePointer();
} }
@ -570,12 +573,12 @@ public:
explicit FixedBytesType(unsigned _bytes); explicit FixedBytesType(unsigned _bytes);
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) 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 calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
unsigned storageBytes() const override { return m_bytes; } unsigned storageBytes() const override { return m_bytes; }
@ -601,8 +604,8 @@ public:
BoolType() {} BoolType() {}
Category category() const override { return Category::Bool; } Category category() const override { return Category::Bool; }
std::string richIdentifier() const override { return "t_bool"; } std::string richIdentifier() const override { return "t_bool"; }
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override; TypeResult binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; } unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
unsigned storageBytes() const override { return 1; } unsigned storageBytes() const override { return 1; }
@ -624,8 +627,8 @@ public:
explicit ReferenceType(DataLocation _location): m_location(_location) {} explicit ReferenceType(DataLocation _location): m_location(_location) {}
DataLocation location() const { return m_location; } DataLocation location() const { return m_location; }
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token, TypePointer const&) const override TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{ {
return TypePointer(); return TypePointer();
} }
@ -702,8 +705,8 @@ public:
m_length(_length) m_length(_length)
{} {}
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(const Type& _other) const override; bool operator==(const Type& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override; unsigned calldataEncodedSize(bool _padded) const override;
@ -757,10 +760,10 @@ public:
explicit ContractType(ContractDefinition const& _contract, bool _super = false): explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {} m_contract(_contract), m_super(_super) {}
/// Contracts can be implicitly converted only to base contracts. /// 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. /// Contracts can only be explicitly converted to address types and base contracts.
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded ) const override unsigned calldataEncodedSize(bool _padded ) const override
@ -821,7 +824,7 @@ public:
Category category() const override { return Category::Struct; } Category category() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage): explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {} ReferenceType(_location), m_struct(_struct) {}
bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(const Type& _convertTo) const override;
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override; unsigned calldataEncodedSize(bool _padded) const override;
@ -876,7 +879,7 @@ class EnumType: public Type
public: public:
Category category() const override { return Category::Enum; } Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_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; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
unsigned calldataEncodedSize(bool _padded) const override unsigned calldataEncodedSize(bool _padded) const override
@ -889,7 +892,7 @@ public:
std::string canonicalName() const override; std::string canonicalName() const override;
bool isValueType() const override { return true; } bool isValueType() const override { return true; }
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer encodingType() const override TypePointer encodingType() const override
{ {
return std::make_shared<IntegerType>(8 * int(storageBytes())); return std::make_shared<IntegerType>(8 * int(storageBytes()));
@ -917,10 +920,10 @@ class TupleType: public Type
public: public:
Category category() const override { return Category::Tuple; } Category category() const override { return Category::Tuple; }
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {} 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; std::string richIdentifier() const override;
bool operator==(Type const& _other) 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; std::string toString(bool) const override;
bool canBeStored() const override { return false; } bool canBeStored() const override { return false; }
u256 storageSize() const override; u256 storageSize() const override;
@ -1065,10 +1068,10 @@ public:
std::string richIdentifier() const override; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isImplicitlyConvertibleTo(Type const& _convertTo) const override;
bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
TypePointer unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
TypePointer binaryOperatorResult(Token, TypePointer const&) const override; TypeResult binaryOperatorResult(Token, TypePointer const&) const override;
std::string canonicalName() const override; std::string canonicalName() const override;
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
unsigned calldataEncodedSize(bool _padded) const override; unsigned calldataEncodedSize(bool _padded) const override;
@ -1197,7 +1200,7 @@ public:
std::string toString(bool _short) const override; std::string toString(bool _short) const override;
std::string canonicalName() const override; std::string canonicalName() const override;
bool canLiveOutsideStorage() const override { return false; } 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 TypePointer encodingType() const override
{ {
return std::make_shared<IntegerType>(256); return std::make_shared<IntegerType>(256);
@ -1230,7 +1233,7 @@ public:
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& actualType() const { return m_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; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; } bool canBeStored() const override { return false; }
@ -1255,7 +1258,7 @@ public:
Category category() const override { return Category::Modifier; } Category category() const override { return Category::Modifier; }
explicit ModifierType(ModifierDefinition const& _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; } bool canBeStored() const override { return false; }
u256 storageSize() const override; u256 storageSize() const override;
bool canLiveOutsideStorage() const override { return false; } bool canLiveOutsideStorage() const override { return false; }
@ -1281,7 +1284,7 @@ public:
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {} 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; std::string richIdentifier() const override;
bool operator==(Type const& _other) const override; bool operator==(Type const& _other) const override;
bool canBeStored() const override { return false; } bool canBeStored() const override { return false; }
@ -1308,7 +1311,7 @@ public:
explicit MagicType(Kind _kind): m_kind(_kind) {} explicit MagicType(Kind _kind): m_kind(_kind) {}
TypePointer binaryOperatorResult(Token, TypePointer const&) const override TypeResult binaryOperatorResult(Token, TypePointer const&) const override
{ {
return TypePointer(); return TypePointer();
} }
@ -1339,9 +1342,9 @@ public:
Category category() const override { return Category::InaccessibleDynamic; } Category category() const override { return Category::InaccessibleDynamic; }
std::string richIdentifier() const override { return "t_inaccessible"; } std::string richIdentifier() const override { return "t_inaccessible"; }
bool isImplicitlyConvertibleTo(Type const&) const override { return false; } BoolResult isImplicitlyConvertibleTo(Type const&) const override { return false; }
bool isExplicitlyConvertibleTo(Type const&) const override { return false; } BoolResult isExplicitlyConvertibleTo(Type const&) const override { return false; }
TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); } TypeResult binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; } unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
bool canBeStored() const override { return false; } bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return false; } bool canLiveOutsideStorage() const override { return false; }