mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4887 from ethereum/addressSplit
Split IntegerType into IntegerType and AddressType.
This commit is contained in:
commit
08a7a51f07
@ -86,6 +86,7 @@ Compiler Features:
|
|||||||
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
|
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
|
||||||
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
|
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
|
||||||
* Type Checker: Show named argument in case of error.
|
* Type Checker: Show named argument in case of error.
|
||||||
|
* Type System: IntegerType is split into IntegerType and AddressType internally.
|
||||||
* Tests: Determine transaction status during IPC calls.
|
* Tests: Determine transaction status during IPC calls.
|
||||||
* Code Generator: Allocate and free local variables according to their scope.
|
* Code Generator: Allocate and free local variables according to their scope.
|
||||||
* Removed ``pragma experimental "v0.5.0";``.
|
* Removed ``pragma experimental "v0.5.0";``.
|
||||||
|
@ -2103,7 +2103,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
"after argument-dependent lookup in " + exprType->toString() +
|
"after argument-dependent lookup in " + exprType->toString() +
|
||||||
(memberName == "value" ? " - did you forget the \"payable\" modifier?" : ".");
|
(memberName == "value" ? " - did you forget the \"payable\" modifier?" : ".");
|
||||||
if (exprType->category() == Type::Category::Contract)
|
if (exprType->category() == Type::Category::Contract)
|
||||||
for (auto const& addressMember: IntegerType(160, IntegerType::Modifier::Address).nativeMembers(nullptr))
|
for (auto const& addressMember: AddressType().nativeMembers(nullptr))
|
||||||
if (addressMember.name == memberName)
|
if (addressMember.name == memberName)
|
||||||
{
|
{
|
||||||
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||||
@ -2353,7 +2353,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
|||||||
if (_literal.looksLikeAddress())
|
if (_literal.looksLikeAddress())
|
||||||
{
|
{
|
||||||
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
|
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
|
||||||
_literal.annotation().type = make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
_literal.annotation().type = make_shared<AddressType>();
|
||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
if (_literal.value().length() != 42) // "0x" + 40 hex digits
|
if (_literal.value().length() != 42) // "0x" + 40 hex digits
|
||||||
|
@ -323,7 +323,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
|
|||||||
ASTString const& member = _memberAccess.memberName();
|
ASTString const& member = _memberAccess.memberName();
|
||||||
switch (_memberAccess.expression().annotation().type->category())
|
switch (_memberAccess.expression().annotation().type->category())
|
||||||
{
|
{
|
||||||
case Type::Category::Integer:
|
case Type::Category::Address:
|
||||||
if (member == "balance")
|
if (member == "balance")
|
||||||
mutability = StateMutability::View;
|
mutability = StateMutability::View;
|
||||||
break;
|
break;
|
||||||
|
@ -299,7 +299,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
|
|||||||
case Token::Byte:
|
case Token::Byte:
|
||||||
return make_shared<FixedBytesType>(1);
|
return make_shared<FixedBytesType>(1);
|
||||||
case Token::Address:
|
case Token::Address:
|
||||||
return make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
return make_shared<AddressType>();
|
||||||
case Token::Bool:
|
case Token::Bool:
|
||||||
return make_shared<BoolType>();
|
return make_shared<BoolType>();
|
||||||
case Token::Bytes:
|
case Token::Bytes:
|
||||||
@ -439,6 +439,59 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
|
|||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AddressType::richIdentifier() const
|
||||||
|
{
|
||||||
|
return "t_address";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
|
{
|
||||||
|
return isImplicitlyConvertibleTo(_convertTo) ||
|
||||||
|
_convertTo.category() == Category::Contract ||
|
||||||
|
_convertTo.category() == Category::Integer ||
|
||||||
|
(_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
string AddressType::toString(bool) const
|
||||||
|
{
|
||||||
|
return "address";
|
||||||
|
}
|
||||||
|
|
||||||
|
u256 AddressType::literalValue(Literal const* _literal) const
|
||||||
|
{
|
||||||
|
solAssert(_literal, "");
|
||||||
|
solAssert(_literal->value().substr(0, 2) == "0x", "");
|
||||||
|
return u256(_literal->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePointer AddressType::unaryOperatorResult(Token::Value _operator) const
|
||||||
|
{
|
||||||
|
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TypePointer AddressType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
|
||||||
|
{
|
||||||
|
// Addresses can only be compared.
|
||||||
|
if (!Token::isCompareOp(_operator))
|
||||||
|
return TypePointer();
|
||||||
|
|
||||||
|
return Type::commonType(shared_from_this(), _other);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{"balance", make_shared<IntegerType>(256)},
|
||||||
|
{"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
|
||||||
|
{"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
|
||||||
|
{"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
|
||||||
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
||||||
|
{"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
|
||||||
|
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -448,7 +501,7 @@ bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountT
|
|||||||
if (_operator == Token::SHR)
|
if (_operator == Token::SHR)
|
||||||
return false;
|
return false;
|
||||||
else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType))
|
else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType))
|
||||||
return !otherInt->isAddress();
|
return true;
|
||||||
else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType))
|
else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType))
|
||||||
return !otherRat->isFractional() && otherRat->integerType() && !otherRat->integerType()->isSigned();
|
return !otherRat->isFractional() && otherRat->integerType() && !otherRat->integerType()->isSigned();
|
||||||
else
|
else
|
||||||
@ -460,8 +513,6 @@ bool isValidShiftAndAmountType(Token::Value _operator, Type const& _shiftAmountT
|
|||||||
IntegerType::IntegerType(unsigned _bits, IntegerType::Modifier _modifier):
|
IntegerType::IntegerType(unsigned _bits, IntegerType::Modifier _modifier):
|
||||||
m_bits(_bits), m_modifier(_modifier)
|
m_bits(_bits), m_modifier(_modifier)
|
||||||
{
|
{
|
||||||
if (isAddress())
|
|
||||||
solAssert(m_bits == 160, "");
|
|
||||||
solAssert(
|
solAssert(
|
||||||
m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
|
m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
|
||||||
"Invalid bit number for integer type: " + dev::toString(m_bits)
|
"Invalid bit number for integer type: " + dev::toString(m_bits)
|
||||||
@ -470,9 +521,6 @@ IntegerType::IntegerType(unsigned _bits, IntegerType::Modifier _modifier):
|
|||||||
|
|
||||||
string IntegerType::richIdentifier() const
|
string IntegerType::richIdentifier() const
|
||||||
{
|
{
|
||||||
if (isAddress())
|
|
||||||
return "t_address";
|
|
||||||
else
|
|
||||||
return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits());
|
return "t_" + string(isSigned() ? "" : "u") + "int" + to_string(numBits());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,8 +531,6 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
|
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
|
||||||
if (convertTo.m_bits < m_bits)
|
if (convertTo.m_bits < m_bits)
|
||||||
return false;
|
return false;
|
||||||
if (isAddress())
|
|
||||||
return convertTo.isAddress();
|
|
||||||
else if (isSigned())
|
else if (isSigned())
|
||||||
return convertTo.isSigned();
|
return convertTo.isSigned();
|
||||||
else
|
else
|
||||||
@ -493,10 +539,6 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
else if (_convertTo.category() == Category::FixedPoint)
|
else if (_convertTo.category() == Category::FixedPoint)
|
||||||
{
|
{
|
||||||
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
|
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
|
||||||
|
|
||||||
if (isAddress())
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return maxValue() <= convertTo.maxIntegerValue() && minValue() >= convertTo.minIntegerValue();
|
return maxValue() <= convertTo.maxIntegerValue() && minValue() >= convertTo.minIntegerValue();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -506,6 +548,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
return _convertTo.category() == category() ||
|
return _convertTo.category() == category() ||
|
||||||
|
_convertTo.category() == Category::Address ||
|
||||||
_convertTo.category() == Category::Contract ||
|
_convertTo.category() == Category::Contract ||
|
||||||
_convertTo.category() == Category::Enum ||
|
_convertTo.category() == Category::Enum ||
|
||||||
(_convertTo.category() == Category::FixedBytes && numBits() == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8) ||
|
(_convertTo.category() == Category::FixedBytes && numBits() == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8) ||
|
||||||
@ -517,10 +560,7 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _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 make_shared<TupleType>();
|
||||||
// no further unary operators for addresses
|
// we allow +, -, ++ and --
|
||||||
else if (isAddress())
|
|
||||||
return TypePointer();
|
|
||||||
// for non-address integers, 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)
|
||||||
@ -539,20 +579,10 @@ bool IntegerType::operator==(Type const& _other) const
|
|||||||
|
|
||||||
string IntegerType::toString(bool) const
|
string IntegerType::toString(bool) const
|
||||||
{
|
{
|
||||||
if (isAddress())
|
|
||||||
return "address";
|
|
||||||
string prefix = isSigned() ? "int" : "uint";
|
string prefix = isSigned() ? "int" : "uint";
|
||||||
return prefix + dev::toString(m_bits);
|
return prefix + dev::toString(m_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 IntegerType::literalValue(Literal const* _literal) const
|
|
||||||
{
|
|
||||||
solAssert(m_modifier == Modifier::Address, "");
|
|
||||||
solAssert(_literal, "");
|
|
||||||
solAssert(_literal->value().substr(0, 2) == "0x", "");
|
|
||||||
return u256(_literal->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
bigint IntegerType::minValue() const
|
bigint IntegerType::minValue() const
|
||||||
{
|
{
|
||||||
if (isSigned())
|
if (isSigned())
|
||||||
@ -580,8 +610,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
|||||||
if (Token::isShiftOp(_operator))
|
if (Token::isShiftOp(_operator))
|
||||||
{
|
{
|
||||||
// Shifts are not symmetric with respect to the type
|
// Shifts are not symmetric with respect to the type
|
||||||
if (isAddress())
|
|
||||||
return TypePointer();
|
|
||||||
if (isValidShiftAndAmountType(_operator, *_other))
|
if (isValidShiftAndAmountType(_operator, *_other))
|
||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
else
|
else
|
||||||
@ -599,9 +627,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
|||||||
return TypePointer();
|
return TypePointer();
|
||||||
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
|
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
|
||||||
{
|
{
|
||||||
// Nothing else can be done with addresses
|
|
||||||
if (intType->isAddress())
|
|
||||||
return TypePointer();
|
|
||||||
// Signed EXP is not allowed
|
// Signed EXP is not allowed
|
||||||
if (Token::Exp == _operator && intType->isSigned())
|
if (Token::Exp == _operator && intType->isSigned())
|
||||||
return TypePointer();
|
return TypePointer();
|
||||||
@ -612,22 +637,6 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
|||||||
return commonType;
|
return commonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) const
|
|
||||||
{
|
|
||||||
if (isAddress())
|
|
||||||
return {
|
|
||||||
{"balance", make_shared<IntegerType>(256)},
|
|
||||||
{"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
|
|
||||||
{"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
|
|
||||||
{"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
|
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
|
||||||
{"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
|
|
||||||
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
|
||||||
};
|
|
||||||
else
|
|
||||||
return MemberList::MemberMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
FixedPointType::FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, FixedPointType::Modifier _modifier):
|
FixedPointType::FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, FixedPointType::Modifier _modifier):
|
||||||
m_totalBits(_totalBits), m_fractionalDigits(_fractionalDigits), m_modifier(_modifier)
|
m_totalBits(_totalBits), m_fractionalDigits(_fractionalDigits), m_modifier(_modifier)
|
||||||
{
|
{
|
||||||
@ -658,8 +667,7 @@ bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
|
|
||||||
bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
return _convertTo.category() == category() ||
|
return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
|
||||||
(_convertTo.category() == Category::Integer && !dynamic_cast<IntegerType const&>(_convertTo).isAddress());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
|
TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const
|
||||||
@ -912,8 +920,6 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
if (isFractional())
|
if (isFractional())
|
||||||
return false;
|
return false;
|
||||||
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
|
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo);
|
||||||
if (targetType.isAddress())
|
|
||||||
return false;
|
|
||||||
if (m_value == rational(0))
|
if (m_value == rational(0))
|
||||||
return true;
|
return true;
|
||||||
unsigned forSignBit = (targetType.isSigned() ? 1 : 0);
|
unsigned forSignBit = (targetType.isSigned() ? 1 : 0);
|
||||||
@ -1368,6 +1374,7 @@ bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool 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::FixedPoint ||
|
_convertTo.category() == Category::FixedPoint ||
|
||||||
_convertTo.category() == category();
|
_convertTo.category() == category();
|
||||||
}
|
}
|
||||||
@ -1469,9 +1476,7 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
|
|
||||||
bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
return
|
return isImplicitlyConvertibleTo(_convertTo) || _convertTo.category() == Category::Address;
|
||||||
isImplicitlyConvertibleTo(_convertTo) ||
|
|
||||||
_convertTo == IntegerType(160, IntegerType::Modifier::Address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContractType::isPayable() const
|
bool ContractType::isPayable() const
|
||||||
@ -2584,12 +2589,8 @@ bool FunctionType::operator==(Type const& _other) const
|
|||||||
|
|
||||||
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
if (m_kind == Kind::External && _convertTo.category() == Category::Integer)
|
if (m_kind == Kind::External && _convertTo.category() == Category::Address)
|
||||||
{
|
|
||||||
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
|
|
||||||
if (convertTo.isAddress())
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return _convertTo.category() == category();
|
return _convertTo.category() == category();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3274,7 +3275,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
|||||||
{
|
{
|
||||||
case Kind::Block:
|
case Kind::Block:
|
||||||
return MemberList::MemberMap({
|
return MemberList::MemberMap({
|
||||||
{"coinbase", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
|
{"coinbase", make_shared<AddressType>()},
|
||||||
{"timestamp", make_shared<IntegerType>(256)},
|
{"timestamp", make_shared<IntegerType>(256)},
|
||||||
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
|
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
|
||||||
{"difficulty", make_shared<IntegerType>(256)},
|
{"difficulty", make_shared<IntegerType>(256)},
|
||||||
@ -3283,7 +3284,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
|||||||
});
|
});
|
||||||
case Kind::Message:
|
case Kind::Message:
|
||||||
return MemberList::MemberMap({
|
return MemberList::MemberMap({
|
||||||
{"sender", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
|
{"sender", make_shared<AddressType>()},
|
||||||
{"gas", make_shared<IntegerType>(256)},
|
{"gas", make_shared<IntegerType>(256)},
|
||||||
{"value", make_shared<IntegerType>(256)},
|
{"value", make_shared<IntegerType>(256)},
|
||||||
{"data", make_shared<ArrayType>(DataLocation::CallData)},
|
{"data", make_shared<ArrayType>(DataLocation::CallData)},
|
||||||
@ -3291,7 +3292,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
|||||||
});
|
});
|
||||||
case Kind::Transaction:
|
case Kind::Transaction:
|
||||||
return MemberList::MemberMap({
|
return MemberList::MemberMap({
|
||||||
{"origin", make_shared<IntegerType>(160, IntegerType::Modifier::Address)},
|
{"origin", make_shared<AddressType>()},
|
||||||
{"gasprice", make_shared<IntegerType>(256)}
|
{"gasprice", make_shared<IntegerType>(256)}
|
||||||
});
|
});
|
||||||
case Kind::ABI:
|
case Kind::ABI:
|
||||||
|
@ -141,7 +141,7 @@ public:
|
|||||||
virtual ~Type() = default;
|
virtual ~Type() = default;
|
||||||
enum class Category
|
enum class Category
|
||||||
{
|
{
|
||||||
Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array,
|
||||||
FixedBytes, Contract, Struct, Function, Enum, Tuple,
|
FixedBytes, Contract, Struct, Function, Enum, Tuple,
|
||||||
Mapping, TypeType, Modifier, Magic, Module,
|
Mapping, TypeType, Modifier, Magic, Module,
|
||||||
InaccessibleDynamic
|
InaccessibleDynamic
|
||||||
@ -314,14 +314,45 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any kind of integer type (signed, unsigned, address).
|
* Type for addresses.
|
||||||
|
*/
|
||||||
|
class AddressType: public Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Category category() const override { return Category::Address; }
|
||||||
|
|
||||||
|
explicit AddressType()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string richIdentifier() const override;
|
||||||
|
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
|
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||||
|
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
|
||||||
|
|
||||||
|
virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; }
|
||||||
|
virtual unsigned storageBytes() const override { return 160 / 8; }
|
||||||
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||||
|
|
||||||
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
|
virtual u256 literalValue(Literal const* _literal) const override;
|
||||||
|
|
||||||
|
virtual TypePointer encodingType() const override { return shared_from_this(); }
|
||||||
|
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any kind of integer type (signed, unsigned).
|
||||||
*/
|
*/
|
||||||
class IntegerType: public Type
|
class IntegerType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Modifier
|
enum class Modifier
|
||||||
{
|
{
|
||||||
Unsigned, Signed, Address
|
Unsigned, Signed
|
||||||
};
|
};
|
||||||
virtual Category category() const override { return Category::Integer; }
|
virtual Category category() const override { return Category::Integer; }
|
||||||
|
|
||||||
@ -339,17 +370,12 @@ public:
|
|||||||
virtual unsigned storageBytes() const override { return m_bits / 8; }
|
virtual unsigned storageBytes() const override { return m_bits / 8; }
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
|
||||||
|
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
virtual u256 literalValue(Literal const* _literal) const override;
|
|
||||||
|
|
||||||
virtual TypePointer encodingType() const override { return shared_from_this(); }
|
virtual TypePointer encodingType() const override { return shared_from_this(); }
|
||||||
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||||
|
|
||||||
unsigned numBits() const { return m_bits; }
|
unsigned numBits() const { return m_bits; }
|
||||||
bool isAddress() const { return m_modifier == Modifier::Address; }
|
|
||||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||||
|
|
||||||
bigint minValue() const;
|
bigint minValue() const;
|
||||||
@ -729,7 +755,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (isSuper())
|
if (isSuper())
|
||||||
return TypePointer{};
|
return TypePointer{};
|
||||||
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
return std::make_shared<AddressType>();
|
||||||
}
|
}
|
||||||
virtual TypePointer interfaceType(bool _inLibrary) const override
|
virtual TypePointer interfaceType(bool _inLibrary) const override
|
||||||
{
|
{
|
||||||
|
@ -197,6 +197,9 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
switch (_type.category())
|
switch (_type.category())
|
||||||
{
|
{
|
||||||
|
case Type::Category::Address:
|
||||||
|
templ("body", "cleaned := " + cleanupFunction(IntegerType(160)) + "(value)");
|
||||||
|
break;
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
{
|
{
|
||||||
IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
|
IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
|
||||||
@ -239,7 +242,7 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
templ("body", "cleaned := " + cleanupFunction(IntegerType(160, IntegerType::Modifier::Address)) + "(value)");
|
templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)");
|
||||||
break;
|
break;
|
||||||
case Type::Category::Enum:
|
case Type::Category::Enum:
|
||||||
{
|
{
|
||||||
@ -284,6 +287,12 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
auto fromCategory = _from.category();
|
auto fromCategory = _from.category();
|
||||||
switch (fromCategory)
|
switch (fromCategory)
|
||||||
{
|
{
|
||||||
|
case Type::Category::Address:
|
||||||
|
body =
|
||||||
|
Whiskers("converted := <convert>(value)")
|
||||||
|
("convert", conversionFunction(IntegerType(160), _to))
|
||||||
|
.render();
|
||||||
|
break;
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
@ -314,16 +323,19 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
else if (toCategory == Type::Category::FixedPoint)
|
else if (toCategory == Type::Category::FixedPoint)
|
||||||
{
|
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||||
}
|
else if (toCategory == Type::Category::Address)
|
||||||
|
body =
|
||||||
|
Whiskers("converted := <convert>(value)")
|
||||||
|
("convert", conversionFunction(_from, IntegerType(160)))
|
||||||
|
.render();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
toCategory == Type::Category::Integer ||
|
toCategory == Type::Category::Integer ||
|
||||||
toCategory == Type::Category::Contract,
|
toCategory == Type::Category::Contract,
|
||||||
"");
|
"");
|
||||||
IntegerType const addressType(160, IntegerType::Modifier::Address);
|
IntegerType const addressType(160);
|
||||||
IntegerType const& to =
|
IntegerType const& to =
|
||||||
toCategory == Type::Category::Integer ?
|
toCategory == Type::Category::Integer ?
|
||||||
dynamic_cast<IntegerType const&>(_to) :
|
dynamic_cast<IntegerType const&>(_to) :
|
||||||
@ -375,6 +387,11 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
("shift", shiftRightFunction(256 - from.numBytes() * 8))
|
("shift", shiftRightFunction(256 - from.numBytes() * 8))
|
||||||
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
|
("convert", conversionFunction(IntegerType(from.numBytes() * 8), _to))
|
||||||
.render();
|
.render();
|
||||||
|
else if (toCategory == Type::Category::Address)
|
||||||
|
body =
|
||||||
|
Whiskers("converted := <convert>(value)")
|
||||||
|
("convert", conversionFunction(_from, IntegerType(160)))
|
||||||
|
.render();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// clear for conversion to longer bytes
|
// clear for conversion to longer bytes
|
||||||
@ -410,7 +427,7 @@ string ABIFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(!body.empty(), "");
|
solAssert(!body.empty(), _from.canonicalName() + " to " + _to.canonicalName());
|
||||||
templ("body", body);
|
templ("body", body);
|
||||||
return templ.render();
|
return templ.render();
|
||||||
});
|
});
|
||||||
|
@ -657,6 +657,11 @@ void CompilerUtils::convertType(
|
|||||||
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
|
if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8)
|
||||||
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
|
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
|
||||||
}
|
}
|
||||||
|
else if (targetTypeCategory == Type::Category::Address)
|
||||||
|
{
|
||||||
|
solAssert(typeOnStack.numBytes() * 8 == 160, "");
|
||||||
|
rightShiftNumberOnStack(256 - 160);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// clear for conversion to longer bytes
|
// clear for conversion to longer bytes
|
||||||
@ -690,23 +695,33 @@ void CompilerUtils::convertType(
|
|||||||
break;
|
break;
|
||||||
case Type::Category::FixedPoint:
|
case Type::Category::FixedPoint:
|
||||||
solUnimplemented("Not yet implemented - FixedPointType.");
|
solUnimplemented("Not yet implemented - FixedPointType.");
|
||||||
|
case Type::Category::Address:
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
case Type::Category::Contract:
|
case Type::Category::Contract:
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
if (targetTypeCategory == Type::Category::FixedBytes)
|
if (targetTypeCategory == Type::Category::FixedBytes)
|
||||||
{
|
{
|
||||||
solAssert(stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::RationalNumber,
|
solAssert(
|
||||||
"Invalid conversion to FixedBytesType requested.");
|
stackTypeCategory == Type::Category::Address ||
|
||||||
|
stackTypeCategory == Type::Category::Integer ||
|
||||||
|
stackTypeCategory == Type::Category::RationalNumber,
|
||||||
|
"Invalid conversion to FixedBytesType requested."
|
||||||
|
);
|
||||||
// conversion from bytes to string. no need to clean the high bit
|
// conversion from bytes to string. no need to clean the high bit
|
||||||
// only to shift left because of opposite alignment
|
// only to shift left because of opposite alignment
|
||||||
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
|
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
|
||||||
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
||||||
|
{
|
||||||
if (targetBytesType.numBytes() * 8 > typeOnStack->numBits())
|
if (targetBytesType.numBytes() * 8 > typeOnStack->numBits())
|
||||||
cleanHigherOrderBits(*typeOnStack);
|
cleanHigherOrderBits(*typeOnStack);
|
||||||
|
}
|
||||||
|
else if (stackTypeCategory == Type::Category::Address)
|
||||||
|
solAssert(targetBytesType.numBytes() * 8 == 160, "");
|
||||||
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
|
||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Enum)
|
else if (targetTypeCategory == Type::Category::Enum)
|
||||||
{
|
{
|
||||||
|
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
|
||||||
solAssert(_typeOnStack.mobileType(), "");
|
solAssert(_typeOnStack.mobileType(), "");
|
||||||
// just clean
|
// just clean
|
||||||
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
|
||||||
@ -733,8 +748,8 @@ void CompilerUtils::convertType(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract, "");
|
solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Contract || targetTypeCategory == Type::Category::Address, "");
|
||||||
IntegerType addressType(160, IntegerType::Modifier::Address);
|
IntegerType addressType(160);
|
||||||
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
|
IntegerType const& targetType = targetTypeCategory == Type::Category::Integer
|
||||||
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
|
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
|
||||||
if (stackTypeCategory == Type::Category::RationalNumber)
|
if (stackTypeCategory == Type::Category::RationalNumber)
|
||||||
@ -996,10 +1011,8 @@ void CompilerUtils::convertType(
|
|||||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Integer)
|
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address)
|
||||||
{
|
{
|
||||||
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
|
|
||||||
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
|
|
||||||
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
||||||
solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted.");
|
solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted.");
|
||||||
|
|
||||||
|
@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
identifier = FunctionType(*function).externalIdentifier();
|
identifier = FunctionType(*function).externalIdentifier();
|
||||||
else
|
else
|
||||||
solAssert(false, "Contract member is neither variable nor function.");
|
solAssert(false, "Contract member is neither variable nor function.");
|
||||||
utils().convertType(type, IntegerType(160, IntegerType::Modifier::Address), true);
|
utils().convertType(type, AddressType(), true);
|
||||||
m_context << identifier;
|
m_context << identifier;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1267,12 +1267,17 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
|
{
|
||||||
|
solAssert(false, "Invalid member access to integer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Type::Category::Address:
|
||||||
{
|
{
|
||||||
if (member == "balance")
|
if (member == "balance")
|
||||||
{
|
{
|
||||||
utils().convertType(
|
utils().convertType(
|
||||||
*_memberAccess.expression().annotation().type,
|
*_memberAccess.expression().annotation().type,
|
||||||
IntegerType(160, IntegerType::Modifier::Address),
|
AddressType(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
m_context << Instruction::BALANCE;
|
m_context << Instruction::BALANCE;
|
||||||
@ -1280,11 +1285,11 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member))
|
else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member))
|
||||||
utils().convertType(
|
utils().convertType(
|
||||||
*_memberAccess.expression().annotation().type,
|
*_memberAccess.expression().annotation().type,
|
||||||
IntegerType(160, IntegerType::Modifier::Address),
|
AddressType(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
solAssert(false, "Invalid member access to integer");
|
solAssert(false, "Invalid member access to address");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Function:
|
case Type::Category::Function:
|
||||||
@ -1578,7 +1583,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
|
|||||||
{
|
{
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
case Type::Category::Integer:
|
case Type::Category::Address:
|
||||||
m_context << type->literalValue(&_literal);
|
m_context << type->literalValue(&_literal);
|
||||||
break;
|
break;
|
||||||
case Type::Category::StringLiteral:
|
case Type::Category::StringLiteral:
|
||||||
|
@ -394,7 +394,7 @@ void SMTChecker::endVisit(Identifier const& _identifier)
|
|||||||
void SMTChecker::endVisit(Literal const& _literal)
|
void SMTChecker::endVisit(Literal const& _literal)
|
||||||
{
|
{
|
||||||
Type const& type = *_literal.annotation().type;
|
Type const& type = *_literal.annotation().type;
|
||||||
if (type.category() == Type::Category::Integer || type.category() == Type::Category::RationalNumber)
|
if (type.category() == Type::Category::Integer || type.category() == Type::Category::Address || type.category() == Type::Category::RationalNumber)
|
||||||
{
|
{
|
||||||
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&type))
|
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(&type))
|
||||||
solAssert(!rational->isFractional(), "");
|
solAssert(!rational->isFractional(), "");
|
||||||
@ -540,6 +540,8 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio
|
|||||||
TypePointer type = _variable.type();
|
TypePointer type = _variable.type();
|
||||||
if (auto const* intType = dynamic_cast<IntegerType const*>(type.get()))
|
if (auto const* intType = dynamic_cast<IntegerType const*>(type.get()))
|
||||||
checkUnderOverflow(_value, *intType, _location);
|
checkUnderOverflow(_value, *intType, _location);
|
||||||
|
else if (dynamic_cast<AddressType const*>(type.get()))
|
||||||
|
checkUnderOverflow(_value, IntegerType(160), _location);
|
||||||
m_interface->addAssertion(newValue(_variable) == _value);
|
m_interface->addAssertion(newValue(_variable) == _value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,6 +864,7 @@ void SMTChecker::createExpr(Expression const& _e)
|
|||||||
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
|
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::Category::Address:
|
||||||
case Type::Category::Integer:
|
case Type::Category::Integer:
|
||||||
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
|
m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
|
||||||
break;
|
break;
|
||||||
|
@ -50,7 +50,7 @@ bool SSAVariable::isSupportedType(Type::Category _category)
|
|||||||
|
|
||||||
bool SSAVariable::isInteger(Type::Category _category)
|
bool SSAVariable::isInteger(Type::Category _category)
|
||||||
{
|
{
|
||||||
return _category == Type::Category::Integer;
|
return _category == Type::Category::Integer || _category == Type::Category::Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSAVariable::isBool(Type::Category _category)
|
bool SSAVariable::isBool(Type::Category _category)
|
||||||
|
@ -29,7 +29,11 @@ SymbolicIntVariable::SymbolicIntVariable(
|
|||||||
):
|
):
|
||||||
SymbolicVariable(_decl, _interface)
|
SymbolicVariable(_decl, _interface)
|
||||||
{
|
{
|
||||||
solAssert(m_declaration.type()->category() == Type::Category::Integer, "");
|
solAssert(
|
||||||
|
m_declaration.type()->category() == Type::Category::Integer ||
|
||||||
|
m_declaration.type()->category() == Type::Category::Address,
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
smt::Expression SymbolicIntVariable::valueAtSequence(int _seq) const
|
smt::Expression SymbolicIntVariable::valueAtSequence(int _seq) const
|
||||||
@ -44,9 +48,11 @@ void SymbolicIntVariable::setZeroValue(int _seq)
|
|||||||
|
|
||||||
void SymbolicIntVariable::setUnknownValue(int _seq)
|
void SymbolicIntVariable::setUnknownValue(int _seq)
|
||||||
{
|
{
|
||||||
auto const& intType = dynamic_cast<IntegerType const&>(*m_declaration.type());
|
auto intType = dynamic_pointer_cast<IntegerType const>(m_declaration.type());
|
||||||
m_interface.addAssertion(valueAtSequence(_seq) >= minValue(intType));
|
if (!intType)
|
||||||
m_interface.addAssertion(valueAtSequence(_seq) <= maxValue(intType));
|
intType = make_shared<IntegerType>(160);
|
||||||
|
m_interface.addAssertion(valueAtSequence(_seq) >= minValue(*intType));
|
||||||
|
m_interface.addAssertion(valueAtSequence(_seq) <= maxValue(*intType));
|
||||||
}
|
}
|
||||||
|
|
||||||
smt::Expression SymbolicIntVariable::minValue(IntegerType const& _t)
|
smt::Expression SymbolicIntVariable::minValue(IntegerType const& _t)
|
||||||
|
@ -53,7 +53,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
|
|||||||
|
|
||||||
uint256 count = grants[_to].push(
|
uint256 count = grants[_to].push(
|
||||||
TokenGrant(
|
TokenGrant(
|
||||||
_revokable ? msg.sender : 0, // avoid storing an extra 20 bytes when it is non-revokable
|
_revokable ? msg.sender : 0x0000000000000000000000000000000000000000, // avoid storing an extra 20 bytes when it is non-revokable
|
||||||
_value,
|
_value,
|
||||||
_cliff,
|
_cliff,
|
||||||
_vesting,
|
_vesting,
|
||||||
@ -84,7 +84,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
|
|||||||
revert();
|
revert();
|
||||||
}
|
}
|
||||||
|
|
||||||
address receiver = grant.burnsOnRevoke ? 0xdead : msg.sender;
|
address receiver = grant.burnsOnRevoke ? 0x000000000000000000000000000000000000dEaD : msg.sender;
|
||||||
|
|
||||||
uint256 nonVested = nonVestedTokens(grant, uint64(now));
|
uint256 nonVested = nonVestedTokens(grant, uint64(now));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user