mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
implemented type(X).min and type(X).max for all integer types
This commit is contained in:
@@ -100,11 +100,13 @@ inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariable
|
||||
magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||
magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||
magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)),
|
||||
// Accepts a MagicType that can be any contract type or an Integer type and returns a
|
||||
// MagicType. The TypeChecker handles the correctness of the input and output types.
|
||||
magicVarDecl("type", TypeProvider::function(
|
||||
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
||||
strings{} /* returns a MagicType, handled by the type checker */,
|
||||
strings{},
|
||||
strings{},
|
||||
FunctionType::Kind::MetaType,
|
||||
false,
|
||||
true,
|
||||
StateMutability::Pure
|
||||
)),
|
||||
};
|
||||
|
||||
@@ -214,17 +214,28 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
||||
return {};
|
||||
}
|
||||
TypePointer firstArgType = type(*arguments.front());
|
||||
if (
|
||||
firstArgType->category() != Type::Category::TypeType ||
|
||||
dynamic_cast<TypeType const&>(*firstArgType).actualType()->category() != TypeType::Category::Contract
|
||||
)
|
||||
|
||||
bool wrongType = false;
|
||||
if (firstArgType->category() == Type::Category::TypeType)
|
||||
{
|
||||
TypeType const* typeTypePtr = dynamic_cast<TypeType const*>(firstArgType);
|
||||
Type::Category typeCategory = typeTypePtr->actualType()->category();
|
||||
if (
|
||||
typeCategory != Type::Category::Contract &&
|
||||
typeCategory != Type::Category::Integer
|
||||
)
|
||||
wrongType = true;
|
||||
}
|
||||
else
|
||||
wrongType = true;
|
||||
|
||||
if (wrongType)
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
arguments.front()->location(),
|
||||
"Invalid type for argument in function call. "
|
||||
"Contract type required, but " +
|
||||
type(*arguments.front())->toString(true) +
|
||||
" provided."
|
||||
"Invalid type for argument in the function call. "
|
||||
"A contract type or an integer type is required, but " +
|
||||
type(*arguments.front())->toString(true) + " provided."
|
||||
);
|
||||
return {};
|
||||
}
|
||||
@@ -2600,6 +2611,11 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
annotation.isPure = true;
|
||||
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId")
|
||||
annotation.isPure = true;
|
||||
else if (
|
||||
magicType->kind() == MagicType::Kind::MetaType &&
|
||||
(memberName == "min" || memberName == "max")
|
||||
)
|
||||
annotation.isPure = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -357,6 +357,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
|
||||
{MagicType::Kind::MetaType, "runtimeCode"},
|
||||
{MagicType::Kind::MetaType, "name"},
|
||||
{MagicType::Kind::MetaType, "interfaceId"},
|
||||
{MagicType::Kind::MetaType, "min"},
|
||||
{MagicType::Kind::MetaType, "max"},
|
||||
};
|
||||
set<MagicMember> static const payableMembers{
|
||||
{MagicType::Kind::Message, "value"}
|
||||
|
||||
@@ -556,7 +556,13 @@ MagicType const* TypeProvider::magic(MagicType::Kind _kind)
|
||||
|
||||
MagicType const* TypeProvider::meta(Type const* _type)
|
||||
{
|
||||
solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now.");
|
||||
solAssert(
|
||||
_type && (
|
||||
_type->category() == Type::Category::Contract ||
|
||||
_type->category() == Type::Category::Integer
|
||||
),
|
||||
"Only contracts or integer types supported for now."
|
||||
);
|
||||
return createAndGet<MagicType>(_type);
|
||||
}
|
||||
|
||||
|
||||
+42
-11
@@ -556,6 +556,22 @@ string IntegerType::toString(bool) const
|
||||
return prefix + util::toString(m_bits);
|
||||
}
|
||||
|
||||
u256 IntegerType::min() const
|
||||
{
|
||||
if (isSigned())
|
||||
return s2u(s256(minValue()));
|
||||
else
|
||||
return u256(minValue());
|
||||
}
|
||||
|
||||
u256 IntegerType::max() const
|
||||
{
|
||||
if (isSigned())
|
||||
return s2u(s256(maxValue()));
|
||||
else
|
||||
return u256(maxValue());
|
||||
}
|
||||
|
||||
bigint IntegerType::minValue() const
|
||||
{
|
||||
if (isSigned())
|
||||
@@ -3763,20 +3779,35 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
||||
case Kind::MetaType:
|
||||
{
|
||||
solAssert(
|
||||
m_typeArgument && m_typeArgument->category() == Type::Category::Contract,
|
||||
"Only contracts supported for now"
|
||||
m_typeArgument && (
|
||||
m_typeArgument->category() == Type::Category::Contract ||
|
||||
m_typeArgument->category() == Type::Category::Integer
|
||||
),
|
||||
"Only contracts or integer types supported for now"
|
||||
);
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
|
||||
if (contract.canBeDeployed())
|
||||
|
||||
if (m_typeArgument->category() == Type::Category::Contract)
|
||||
{
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
|
||||
if (contract.canBeDeployed())
|
||||
return MemberList::MemberMap({
|
||||
{"creationCode", TypeProvider::array(DataLocation::Memory)},
|
||||
{"runtimeCode", TypeProvider::array(DataLocation::Memory)},
|
||||
{"name", TypeProvider::stringMemory()},
|
||||
});
|
||||
else
|
||||
return MemberList::MemberMap({
|
||||
{"interfaceId", TypeProvider::fixedBytes(4)},
|
||||
});
|
||||
}
|
||||
else if (m_typeArgument->category() == Type::Category::Integer)
|
||||
{
|
||||
IntegerType const* integerTypePointer = dynamic_cast<IntegerType const*>(m_typeArgument);
|
||||
return MemberList::MemberMap({
|
||||
{"creationCode", TypeProvider::array(DataLocation::Memory)},
|
||||
{"runtimeCode", TypeProvider::array(DataLocation::Memory)},
|
||||
{"name", TypeProvider::stringMemory()},
|
||||
});
|
||||
else
|
||||
return MemberList::MemberMap({
|
||||
{"interfaceId", TypeProvider::fixedBytes(4)},
|
||||
{"min", integerTypePointer},
|
||||
{"max", integerTypePointer},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
solAssert(false, "Unknown kind of magic.");
|
||||
|
||||
@@ -452,6 +452,9 @@ public:
|
||||
unsigned numBits() const { return m_bits; }
|
||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||
|
||||
u256 min() const;
|
||||
u256 max() const;
|
||||
|
||||
bigint minValue() const;
|
||||
bigint maxValue() const;
|
||||
|
||||
|
||||
@@ -1591,6 +1591,16 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
||||
result ^= fromBigEndian<uint64_t>(function.first.ref());
|
||||
m_context << (u256{result} << (256 - 32));
|
||||
}
|
||||
else if (member == "min" || member == "max")
|
||||
{
|
||||
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
||||
IntegerType const* integerType = dynamic_cast<IntegerType const*>(arg->typeArgument());
|
||||
|
||||
if (member == "min")
|
||||
m_context << integerType->min();
|
||||
else
|
||||
m_context << integerType->max();
|
||||
}
|
||||
else if ((set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member))
|
||||
{
|
||||
// no-op
|
||||
|
||||
@@ -477,12 +477,16 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commonType->category() == Type::Category::RationalNumber)
|
||||
{
|
||||
define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n";
|
||||
return false; // skip sub-expressions
|
||||
}
|
||||
|
||||
_binOp.leftExpression().accept(*this);
|
||||
_binOp.rightExpression().accept(*this);
|
||||
|
||||
if (commonType->category() == Type::Category::RationalNumber)
|
||||
define(_binOp) << toCompactHexWithPrefix(commonType->literalValue(nullptr)) << "\n";
|
||||
else if (TokenTraits::isCompareOp(op))
|
||||
if (TokenTraits::isCompareOp(op))
|
||||
{
|
||||
if (auto type = dynamic_cast<FunctionType const*>(commonType))
|
||||
{
|
||||
@@ -1175,6 +1179,16 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
||||
result ^= fromBigEndian<uint64_t>(function.first.ref());
|
||||
define(_memberAccess) << formatNumber(u256{result} << (256 - 32)) << "\n";
|
||||
}
|
||||
else if (member == "min" || member == "max")
|
||||
{
|
||||
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
||||
IntegerType const* integerType = dynamic_cast<IntegerType const*>(arg->typeArgument());
|
||||
|
||||
if (member == "min")
|
||||
define(_memberAccess) << formatNumber(integerType->min()) << "\n";
|
||||
else
|
||||
define(_memberAccess) << formatNumber(integerType->max()) << "\n";
|
||||
}
|
||||
else if (set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}.count(member))
|
||||
{
|
||||
// no-op
|
||||
|
||||
Reference in New Issue
Block a user