mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge 23920b946c
into 72671d6c88
This commit is contained in:
commit
4ffb7a9458
@ -119,6 +119,7 @@ Type Information
|
|||||||
- ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information<meta-type>`.
|
- ``type(C).creationCode`` (``bytes memory``): creation bytecode of the given contract, see :ref:`Type Information<meta-type>`.
|
||||||
- ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information<meta-type>`.
|
- ``type(C).runtimeCode`` (``bytes memory``): runtime bytecode of the given contract, see :ref:`Type Information<meta-type>`.
|
||||||
- ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information<meta-type>`.
|
- ``type(I).interfaceId`` (``bytes4``): value containing the EIP-165 interface identifier of the given interface, see :ref:`Type Information<meta-type>`.
|
||||||
|
- ``type(S).typehash`` (``bytes32``): the typehash of the given struct type ``S``, see :ref:`Type Information<meta-type>`.
|
||||||
- ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information<meta-type>`.
|
- ``type(T).min`` (``T``): the minimum value representable by the integer type ``T``, see :ref:`Type Information<meta-type>`.
|
||||||
- ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information<meta-type>`.
|
- ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information<meta-type>`.
|
||||||
|
|
||||||
|
@ -385,6 +385,13 @@ for an interface type ``I``:
|
|||||||
interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all
|
interface identifier of the given interface ``I``. This identifier is defined as the ``XOR`` of all
|
||||||
function selectors defined within the interface itself - excluding all inherited functions.
|
function selectors defined within the interface itself - excluding all inherited functions.
|
||||||
|
|
||||||
|
The following properties are available for an struct type ``S``:
|
||||||
|
|
||||||
|
``type(S).typehash``:
|
||||||
|
A ``bytes32`` value containing the `EIP-712 <https://eips.ethereum.org/EIPS/eip-712>`_
|
||||||
|
typehash of the given structure ``S``. This identifier is defined as ``keccak256`` of
|
||||||
|
structure name and all the fields with their types, wrapped in braces and separated by commas.
|
||||||
|
|
||||||
The following properties are available for an integer type ``T``:
|
The following properties are available for an integer type ``T``:
|
||||||
|
|
||||||
``type(T).min``
|
``type(T).min``
|
||||||
|
@ -315,6 +315,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
|||||||
wrongType = contractType->isSuper();
|
wrongType = contractType->isSuper();
|
||||||
else if (
|
else if (
|
||||||
typeCategory != Type::Category::Integer &&
|
typeCategory != Type::Category::Integer &&
|
||||||
|
typeCategory != Type::Category::Struct &&
|
||||||
typeCategory != Type::Category::Enum
|
typeCategory != Type::Category::Enum
|
||||||
)
|
)
|
||||||
wrongType = true;
|
wrongType = true;
|
||||||
@ -327,7 +328,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio
|
|||||||
4259_error,
|
4259_error,
|
||||||
arguments.front()->location(),
|
arguments.front()->location(),
|
||||||
"Invalid type for argument in the function call. "
|
"Invalid type for argument in the function call. "
|
||||||
"An enum type, contract type or an integer type is required, but " +
|
"An enum type, contract type, struct type or an integer type is required, but " +
|
||||||
type(*arguments.front())->humanReadableName() + " provided."
|
type(*arguments.front())->humanReadableName() + " provided."
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3390,6 +3391,33 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId")
|
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId")
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
|
else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "typehash")
|
||||||
|
{
|
||||||
|
annotation.isPure = true;
|
||||||
|
auto accessedStructType = dynamic_cast<StructType const*>(magicType->typeArgument());
|
||||||
|
solAssert(accessedStructType, "typehash requested on a non struct type.");
|
||||||
|
|
||||||
|
if (accessedStructType->recursive())
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
9298_error,
|
||||||
|
_memberAccess.location(),
|
||||||
|
"\"typehash\" cannot be used for recursive structs."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& member: accessedStructType->members(currentDefinitionScope()))
|
||||||
|
{
|
||||||
|
if (!member.type->isEIP712AllowedStructMemberType())
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
9518_error,
|
||||||
|
_memberAccess.location(),
|
||||||
|
"\"typehash\" cannot be used for structs with members of \"" + member.type->humanReadableName() + "\" type."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (
|
else if (
|
||||||
magicType->kind() == MagicType::Kind::MetaType &&
|
magicType->kind() == MagicType::Kind::MetaType &&
|
||||||
(memberName == "min" || memberName == "max")
|
(memberName == "min" || memberName == "max")
|
||||||
|
@ -397,6 +397,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{MagicType::Kind::MetaType, "runtimeCode"},
|
{MagicType::Kind::MetaType, "runtimeCode"},
|
||||||
{MagicType::Kind::MetaType, "name"},
|
{MagicType::Kind::MetaType, "name"},
|
||||||
{MagicType::Kind::MetaType, "interfaceId"},
|
{MagicType::Kind::MetaType, "interfaceId"},
|
||||||
|
{MagicType::Kind::MetaType, "typehash"},
|
||||||
{MagicType::Kind::MetaType, "min"},
|
{MagicType::Kind::MetaType, "min"},
|
||||||
{MagicType::Kind::MetaType, "max"},
|
{MagicType::Kind::MetaType, "max"},
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <numeric>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
@ -388,6 +390,67 @@ std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingFo
|
|||||||
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<std::vector>;
|
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<std::vector>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StructDefinition::insertEip712EncodedSubtypes(std::set<std::string>& subtypes) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_members.size(); i++)
|
||||||
|
{
|
||||||
|
Declaration const* declaration = nullptr;
|
||||||
|
|
||||||
|
switch (m_members[i]->type()->category())
|
||||||
|
{
|
||||||
|
case Type::Category::Struct:
|
||||||
|
declaration = m_members[i]->type()->typeDefinition();
|
||||||
|
break;
|
||||||
|
case Type::Category::Array:
|
||||||
|
if (auto const* arrayType = dynamic_cast<ArrayType const*>(m_members[i]->type()))
|
||||||
|
{
|
||||||
|
if (auto finalBaseType = dynamic_cast<StructType const*>(arrayType->finalBaseType(false)))
|
||||||
|
{
|
||||||
|
declaration = finalBaseType->typeDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!declaration)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
||||||
|
{
|
||||||
|
subtypes.insert(structDef->eip712EncodeTypeWithoutSubtypes());
|
||||||
|
structDef->insertEip712EncodedSubtypes(subtypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StructDefinition::eip712EncodeTypeWithoutSubtypes() const
|
||||||
|
{
|
||||||
|
std::string str = name() + "(";
|
||||||
|
for (size_t i = 0; i < m_members.size(); i++)
|
||||||
|
{
|
||||||
|
str += i == 0 ? "" : ",";
|
||||||
|
str += m_members[i]->type()->eip712TypeName() + " " + m_members[i]->name();
|
||||||
|
}
|
||||||
|
return str + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string StructDefinition::eip712EncodeType() const
|
||||||
|
{
|
||||||
|
// std::set enables duplicates elimination and ordered enumeration
|
||||||
|
std::set<std::string> subtypes;
|
||||||
|
insertEip712EncodedSubtypes(subtypes);
|
||||||
|
return std::accumulate(subtypes.begin(), subtypes.end(), eip712EncodeTypeWithoutSubtypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
util::h256 StructDefinition::typehash() const
|
||||||
|
{
|
||||||
|
return util::keccak256(eip712EncodeType());
|
||||||
|
}
|
||||||
|
|
||||||
Type const* StructDefinition::type() const
|
Type const* StructDefinition::type() const
|
||||||
{
|
{
|
||||||
solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker.");
|
solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker.");
|
||||||
|
@ -745,6 +745,18 @@ public:
|
|||||||
|
|
||||||
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
|
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
|
||||||
|
|
||||||
|
/// Fills set with the EIP-712 compatible struct encodings without subtypes concatenated.
|
||||||
|
void insertEip712EncodedSubtypes(std::set<std::string>& subtypes) const;
|
||||||
|
|
||||||
|
/// @returns the EIP-712 compatible struct encoding but without subtypes concatenated.
|
||||||
|
std::string eip712EncodeTypeWithoutSubtypes() const;
|
||||||
|
|
||||||
|
/// @returns the EIP-712 compatible struct encoding with subtypes sorted and concatenated.
|
||||||
|
std::string eip712EncodeType() const;
|
||||||
|
|
||||||
|
/// @returns the EIP-712 compatible typehash of this struct.
|
||||||
|
util::h256 typehash() const;
|
||||||
|
|
||||||
Type const* type() const override;
|
Type const* type() const override;
|
||||||
|
|
||||||
bool isVisibleInDerivedContracts() const override { return true; }
|
bool isVisibleInDerivedContracts() const override { return true; }
|
||||||
|
@ -562,10 +562,11 @@ MagicType const* TypeProvider::meta(Type const* _type)
|
|||||||
solAssert(
|
solAssert(
|
||||||
_type && (
|
_type && (
|
||||||
_type->category() == Type::Category::Contract ||
|
_type->category() == Type::Category::Contract ||
|
||||||
|
_type->category() == Type::Category::Struct ||
|
||||||
_type->category() == Type::Category::Integer ||
|
_type->category() == Type::Category::Integer ||
|
||||||
_type->category() == Type::Category::Enum
|
_type->category() == Type::Category::Enum
|
||||||
),
|
),
|
||||||
"Only enum, contracts or integer types supported for now."
|
"Only enum, contract, struct or integer types supported for now."
|
||||||
);
|
);
|
||||||
return createAndGet<MagicType>(_type);
|
return createAndGet<MagicType>(_type);
|
||||||
}
|
}
|
||||||
|
@ -1886,6 +1886,23 @@ std::string ArrayType::canonicalName() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ArrayType::eip712TypeName() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
if (isString())
|
||||||
|
ret = "string";
|
||||||
|
else if (isByteArrayOrString())
|
||||||
|
ret = "bytes";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = baseType()->eip712TypeName() + "[";
|
||||||
|
if (!isDynamicallySized())
|
||||||
|
ret += length().str();
|
||||||
|
ret += "]";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
std::string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
||||||
{
|
{
|
||||||
if (isByteArrayOrString())
|
if (isByteArrayOrString())
|
||||||
@ -2510,6 +2527,11 @@ std::string StructType::canonicalName() const
|
|||||||
return *m_struct.annotation().canonicalName;
|
return *m_struct.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string StructType::eip712TypeName() const
|
||||||
|
{
|
||||||
|
return this->typeDefinition()->name();
|
||||||
|
}
|
||||||
|
|
||||||
FunctionTypePointer StructType::constructorType() const
|
FunctionTypePointer StructType::constructorType() const
|
||||||
{
|
{
|
||||||
TypePointers paramTypes;
|
TypePointers paramTypes;
|
||||||
@ -4196,15 +4218,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
|
|||||||
});
|
});
|
||||||
case Kind::MetaType:
|
case Kind::MetaType:
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(m_typeArgument, "");
|
||||||
m_typeArgument && (
|
|
||||||
m_typeArgument->category() == Type::Category::Contract ||
|
|
||||||
m_typeArgument->category() == Type::Category::Integer ||
|
|
||||||
m_typeArgument->category() == Type::Category::Enum
|
|
||||||
),
|
|
||||||
"Only enums, contracts or integer types supported for now"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (m_typeArgument->category() == Type::Category::Contract)
|
if (m_typeArgument->category() == Type::Category::Contract)
|
||||||
{
|
{
|
||||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
|
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
|
||||||
@ -4220,6 +4234,12 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
|
|||||||
{"name", TypeProvider::stringMemory()},
|
{"name", TypeProvider::stringMemory()},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (m_typeArgument->category() == Type::Category::Struct)
|
||||||
|
{
|
||||||
|
return MemberList::MemberMap({
|
||||||
|
{"typehash", TypeProvider::fixedBytes(32)},
|
||||||
|
});
|
||||||
|
}
|
||||||
else if (m_typeArgument->category() == Type::Category::Integer)
|
else if (m_typeArgument->category() == Type::Category::Integer)
|
||||||
{
|
{
|
||||||
IntegerType const* integerTypePointer = dynamic_cast<IntegerType const*>(m_typeArgument);
|
IntegerType const* integerTypePointer = dynamic_cast<IntegerType const*>(m_typeArgument);
|
||||||
@ -4236,6 +4256,10 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
|
|||||||
{"max", enumTypePointer},
|
{"max", enumTypePointer},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(false, "Only enums, contracts, structs or integer types supported for now");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
solAssert(false, "Unknown kind of magic.");
|
solAssert(false, "Unknown kind of magic.");
|
||||||
|
@ -357,6 +357,12 @@ public:
|
|||||||
/// @returns the canonical name of this type for use in library function signatures.
|
/// @returns the canonical name of this type for use in library function signatures.
|
||||||
virtual std::string canonicalName() const { return toString(true); }
|
virtual std::string canonicalName() const { return toString(true); }
|
||||||
virtual std::string humanReadableName() const { return toString(); }
|
virtual std::string humanReadableName() const { return toString(); }
|
||||||
|
virtual std::string eip712TypeName() const
|
||||||
|
{
|
||||||
|
solAssert(isEIP712AllowedStructMemberType(), "Invalid type ...");
|
||||||
|
return encodingType()->toString(true);
|
||||||
|
}
|
||||||
|
virtual bool isEIP712AllowedStructMemberType() const { return false; }
|
||||||
/// @returns the signature of this type in external functions, i.e. `uint256` for integers
|
/// @returns the signature of this type in external functions, i.e. `uint256` for integers
|
||||||
/// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName,
|
/// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName,
|
||||||
/// structs are given by canonical name like `ContractName.StructName[2]`.
|
/// structs are given by canonical name like `ContractName.StructName[2]`.
|
||||||
@ -457,6 +463,7 @@ public:
|
|||||||
bool leftAligned() const override { return false; }
|
bool leftAligned() const override { return false; }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||||
|
|
||||||
@ -502,6 +509,7 @@ public:
|
|||||||
bool leftAligned() const override { return false; }
|
bool leftAligned() const override { return false; }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
|
|
||||||
@ -551,6 +559,7 @@ public:
|
|||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
|
std::string eip712TypeName() const override{ solAssert(false, "EIP-712 is not supported for struct members of fixed point type"); }
|
||||||
|
|
||||||
Type const* encodingType() const override { return this; }
|
Type const* encodingType() const override { return this; }
|
||||||
TypeResult interfaceType(bool) const override { return this; }
|
TypeResult interfaceType(bool) const override { return this; }
|
||||||
@ -660,6 +669,8 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
|
|
||||||
@ -698,6 +709,7 @@ public:
|
|||||||
bool leftAligned() const override { return true; }
|
bool leftAligned() const override { return true; }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
|
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||||
@ -726,6 +738,7 @@ public:
|
|||||||
bool leftAligned() const override { return false; }
|
bool leftAligned() const override { return false; }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
std::string toString(bool) const override { return "bool"; }
|
std::string toString(bool) const override { return "bool"; }
|
||||||
u256 literalValue(Literal const* _literal) const override;
|
u256 literalValue(Literal const* _literal) const override;
|
||||||
@ -863,10 +876,12 @@ public:
|
|||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); }
|
bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
|
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
std::string humanReadableName() const override;
|
std::string humanReadableName() const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
std::string eip712TypeName() const override;
|
||||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||||
Type const* encodingType() const override;
|
Type const* encodingType() const override;
|
||||||
@ -924,6 +939,7 @@ public:
|
|||||||
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
BoolResult isImplicitlyConvertibleTo(Type const& _other) const override;
|
||||||
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of array slice type"); }
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
unsigned calldataEncodedSize(bool) const override { solAssert(false, ""); }
|
unsigned calldataEncodedSize(bool) const override { solAssert(false, ""); }
|
||||||
unsigned calldataEncodedTailSize() const override { return 32; }
|
unsigned calldataEncodedTailSize() const override { return 32; }
|
||||||
@ -974,6 +990,7 @@ public:
|
|||||||
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
||||||
bool isValueType() const override { return !isSuper(); }
|
bool isValueType() const override { return !isSuper(); }
|
||||||
bool nameable() const override { return !isSuper(); }
|
bool nameable() const override { return !isSuper(); }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
|
||||||
@ -1036,6 +1053,7 @@ public:
|
|||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
bool containsNestedMapping() const override;
|
bool containsNestedMapping() const override;
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
bool isEIP712AllowedStructMemberType() const override { return true; }
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
|
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||||
@ -1052,6 +1070,7 @@ public:
|
|||||||
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||||
|
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
std::string eip712TypeName() const override;
|
||||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||||
|
|
||||||
/// @returns a function that performs the type conversion between a list of struct members
|
/// @returns a function that performs the type conversion between a list of struct members
|
||||||
@ -1100,6 +1119,7 @@ public:
|
|||||||
bool leftAligned() const override { return false; }
|
bool leftAligned() const override { return false; }
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of Enum type"); }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
bool nameable() const override { return true; }
|
bool nameable() const override { return true; }
|
||||||
|
|
||||||
@ -1187,6 +1207,7 @@ public:
|
|||||||
|
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of user defined value type"); }
|
||||||
std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); }
|
std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1218,6 +1239,8 @@ public:
|
|||||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||||
Type const* mobileType() const override;
|
Type const* mobileType() const override;
|
||||||
|
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of tuple type"); }
|
||||||
|
|
||||||
std::vector<Type const*> const& components() const { return m_components; }
|
std::vector<Type const*> const& components() const { return m_components; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1415,6 +1438,7 @@ public:
|
|||||||
TypeResult binaryOperatorResult(Token, Type const*) const override;
|
TypeResult binaryOperatorResult(Token, Type const*) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
std::string humanReadableName() const override;
|
std::string humanReadableName() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of function type"); }
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
unsigned calldataEncodedSize(bool _padded) const override;
|
unsigned calldataEncodedSize(bool _padded) const override;
|
||||||
bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||||
@ -1551,6 +1575,7 @@ public:
|
|||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
std::string canonicalName() const override;
|
std::string canonicalName() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of mapping type"); }
|
||||||
bool containsNestedMapping() const override { return true; }
|
bool containsNestedMapping() const override { return true; }
|
||||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||||
Type const* encodingType() const override;
|
Type const* encodingType() const override;
|
||||||
@ -1595,6 +1620,7 @@ public:
|
|||||||
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; }
|
||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of type type"); }
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
std::string toString(bool _withoutDataLocation) const override { return "type(" + m_actualType->toString(_withoutDataLocation) + ")"; }
|
std::string toString(bool _withoutDataLocation) const override { return "type(" + m_actualType->toString(_withoutDataLocation) + ")"; }
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||||
@ -1623,6 +1649,7 @@ public:
|
|||||||
u256 storageSize() const override;
|
u256 storageSize() const override;
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
std::string richIdentifier() const override;
|
std::string richIdentifier() const override;
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of modifier type"); }
|
||||||
bool operator==(Type const& _other) const override;
|
bool operator==(Type const& _other) const override;
|
||||||
std::string toString(bool _withoutDataLocation) const override;
|
std::string toString(bool _withoutDataLocation) const override;
|
||||||
protected:
|
protected:
|
||||||
@ -1647,6 +1674,7 @@ 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 canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of module type"); }
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||||
|
|
||||||
@ -1686,6 +1714,7 @@ 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 canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of magic type"); }
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||||
|
|
||||||
@ -1721,6 +1750,7 @@ public:
|
|||||||
unsigned calldataEncodedSize(bool) const override { return 32; }
|
unsigned calldataEncodedSize(bool) const override { return 32; }
|
||||||
bool canBeStored() const override { return false; }
|
bool canBeStored() const override { return false; }
|
||||||
bool isValueType() const override { return true; }
|
bool isValueType() const override { return true; }
|
||||||
|
std::string eip712TypeName() const override { solAssert(false, "EIP-712 is not supported for struct members of inaccessible dynamic type"); }
|
||||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||||
Type const* decodingType() const override;
|
Type const* decodingType() const override;
|
||||||
|
@ -1934,6 +1934,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
|
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
|
||||||
m_context << (u256{contract.interfaceId()} << (256 - 32));
|
m_context << (u256{contract.interfaceId()} << (256 - 32));
|
||||||
}
|
}
|
||||||
|
else if (member == "typehash")
|
||||||
|
{
|
||||||
|
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
||||||
|
solAssert(dynamic_cast<StructType const*>(arg), "typehash called on a non-struct type");
|
||||||
|
StructDefinition const& struct_ = dynamic_cast<StructType const&>(*arg).structDefinition();
|
||||||
|
m_context << struct_.typehash();
|
||||||
|
}
|
||||||
else if (member == "min" || member == "max")
|
else if (member == "min" || member == "max")
|
||||||
{
|
{
|
||||||
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
||||||
|
@ -1940,6 +1940,15 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
ContractDefinition const& contract = contractType.contractDefinition();
|
ContractDefinition const& contract = contractType.contractDefinition();
|
||||||
define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n";
|
define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n";
|
||||||
}
|
}
|
||||||
|
else if (member == "typehash")
|
||||||
|
{
|
||||||
|
Type const* arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
|
||||||
|
solAssert(!!arg);
|
||||||
|
StructType const* structType = dynamic_cast<StructType const*>(arg);
|
||||||
|
solAssert(!!structType);
|
||||||
|
StructDefinition const& struct_ = structType->structDefinition();
|
||||||
|
define(_memberAccess) << "0x" << struct_.typehash() << "\n";
|
||||||
|
}
|
||||||
else if (member == "min" || member == "max")
|
else if (member == "min" || member == "max")
|
||||||
{
|
{
|
||||||
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
|
||||||
|
@ -1409,6 +1409,11 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
|
|||||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*magicType->typeArgument()).contractDefinition();
|
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*magicType->typeArgument()).contractDefinition();
|
||||||
defineExpr(_memberAccess, contract.interfaceId());
|
defineExpr(_memberAccess, contract.interfaceId());
|
||||||
}
|
}
|
||||||
|
else if (memberName == "typehash")
|
||||||
|
{
|
||||||
|
StructDefinition const& structDef = dynamic_cast<StructType const&>(*magicType->typeArgument()).structDefinition();
|
||||||
|
defineExpr(_memberAccess, u256(structDef.typehash()));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not
|
// NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not
|
||||||
// at all usable in the SMT checker currently
|
// at all usable in the SMT checker currently
|
||||||
|
@ -1916,6 +1916,9 @@ BOOST_AUTO_TEST_CASE(builtins)
|
|||||||
interface I {}
|
interface I {}
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint x;
|
||||||
|
}
|
||||||
function accessBuiltin() public payable {
|
function accessBuiltin() public payable {
|
||||||
abi.decode;
|
abi.decode;
|
||||||
abi.encode;
|
abi.encode;
|
||||||
@ -1956,6 +1959,7 @@ BOOST_AUTO_TEST_CASE(builtins)
|
|||||||
address(0).staticcall;
|
address(0).staticcall;
|
||||||
type(C).name;
|
type(C).name;
|
||||||
type(I).interfaceId;
|
type(I).interfaceId;
|
||||||
|
type(S).typehash;
|
||||||
type(uint).min;
|
type(uint).min;
|
||||||
type(uint).max;
|
type(uint).max;
|
||||||
assert;
|
assert;
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
struct Mail {
|
||||||
|
address from;
|
||||||
|
address to;
|
||||||
|
string contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure returns(bool) {
|
||||||
|
return type(Mail).typehash == keccak256("Mail(address from,address to,string contents)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// f() -> true
|
@ -0,0 +1,23 @@
|
|||||||
|
library A {
|
||||||
|
struct S1 {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 internal constant a = type(S1).typehash;
|
||||||
|
}
|
||||||
|
|
||||||
|
library B {
|
||||||
|
struct S1 {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 internal constant b = type(S1).typehash;
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns(bool) {
|
||||||
|
return A.a == B.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// f() -> true
|
@ -0,0 +1,26 @@
|
|||||||
|
contract C {
|
||||||
|
struct S2 {
|
||||||
|
uint256 x;
|
||||||
|
S1 y;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S1 {
|
||||||
|
uint256 z;
|
||||||
|
S3[] w;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S3 {
|
||||||
|
address a;
|
||||||
|
uint24 b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure returns(bool, bool, bool) {
|
||||||
|
return (
|
||||||
|
type(S3).typehash == keccak256("S3(address a,uint24 b)"),
|
||||||
|
type(S1).typehash == keccak256("S1(uint256 z,S3[] w)S3(address a,uint24 b)"),
|
||||||
|
type(S2).typehash == keccak256("S2(uint256 x,S1 y)S1(uint256 z,S3[] w)S3(address a,uint24 b)")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// f() -> true, true, true
|
@ -0,0 +1,21 @@
|
|||||||
|
struct S {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 constant TYPE_HASH_FILE_LEVEL = type(S).typehash;
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256 y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure returns(bool, bool, bool) {
|
||||||
|
return (
|
||||||
|
type(S).typehash == keccak256("S(uint256 y)"),
|
||||||
|
type(S).typehash == TYPE_HASH_FILE_LEVEL,
|
||||||
|
TYPE_HASH_FILE_LEVEL == keccak256("S(uint256 x)")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// f() -> true, false, true
|
@ -0,0 +1,14 @@
|
|||||||
|
contract A {
|
||||||
|
struct S {
|
||||||
|
string x;
|
||||||
|
bool[10][] y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C is A {
|
||||||
|
function f() public pure returns(bool) {
|
||||||
|
return type(S).typehash == keccak256("S(string x,bool[10][] y)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// f() -> true
|
43
test/libsolidity/smtCheckerTests/types/type_typehash.sol
Normal file
43
test/libsolidity/smtCheckerTests/types/type_typehash.sol
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
interface I1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
struct S1 {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S2 {
|
||||||
|
uint256 x;
|
||||||
|
address y;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S3 {
|
||||||
|
uint256 x;
|
||||||
|
I1 y;
|
||||||
|
S2 third;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S4 {
|
||||||
|
S3 one;
|
||||||
|
S2 two;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S5 {
|
||||||
|
S2 two;
|
||||||
|
S1 one;
|
||||||
|
S3 three;
|
||||||
|
S4[5] four;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure {
|
||||||
|
assert(type(S1).typehash == 0x78a822935e38445215ba7404686b919cbbef5725cbf9231d92802f542d7456e0); // keccak256("S1(uint256 x)")
|
||||||
|
assert(type(S2).typehash == 0x6c397ebd50462a81423e44830702ee1214cb9ab734bf173eb55f04238c9d398f); // keccak256("S2(uint256 x,address y)")
|
||||||
|
assert(type(S3).typehash == 0xfa5685568fb2f15c09479ecbcfe9d0494743d804587d1966db67d5e62ea4344a); // keccak256("S3(uint256 x,address y,S2 third)S2(uint256 x,address y)")
|
||||||
|
assert(type(S4).typehash == 0x17ed8da37c0446eeffef8cd38d116505b399b5644fdc3a59f8a68a68dd5d4178); // keccak256("S4(S3 one,S2 two)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)")
|
||||||
|
assert(type(S5).typehash == 0x5e52252fbbc0eda2d75f57c57d47fbec3bc6b215a9a3790c7f7ca44a36eb5185); // keccak256("S5(S2 two,S1 one,S3 three,S4[5] four)S1(uint256 x)S2(uint256 x,address y)S3(uint256 x,address y,S2 third)S4(S3 one,S2 two)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// SMTEngine: all
|
||||||
|
// ----
|
||||||
|
// Info 1391: CHC: 5 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
|
@ -5,4 +5,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (93-98): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(bytes storage pointer) provided.
|
// TypeError 4259: (93-98): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(bytes storage pointer) provided.
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (126-139): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but error MyCustomError(uint256,bool) provided.
|
// TypeError 4259: (126-139): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but error MyCustomError(uint256,bool) provided.
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (124-137): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but event MyCustomEvent(uint256) provided.
|
// TypeError 4259: (124-137): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but event MyCustomEvent(uint256) provided.
|
||||||
|
@ -10,4 +10,4 @@ contract SuperTest is Other {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (177-182): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super SuperTest) provided.
|
// TypeError 4259: (177-182): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super SuperTest) provided.
|
||||||
|
@ -14,4 +14,4 @@ abstract contract Test is ERC165 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (592-597): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super Test) provided.
|
// TypeError 4259: (592-597): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super Test) provided.
|
||||||
|
@ -50,4 +50,4 @@ contract D is B, C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (426-431): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super B) provided.
|
// TypeError 4259: (426-431): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract super B) provided.
|
||||||
|
@ -4,4 +4,4 @@ contract Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (65-75): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract Test) provided.
|
// TypeError 4259: (65-75): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(contract Test) provided.
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
contract Test {
|
contract Test {
|
||||||
struct S { uint x; }
|
|
||||||
function f() public pure {
|
function f() public pure {
|
||||||
// Unsupported for now, but might be supported in the future
|
// Unsupported for now, but might be supported in the future
|
||||||
type(S);
|
type(bytes32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4259: (154-155): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(struct Test.S storage pointer) provided.
|
// TypeError 4259: (129-136): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(bytes32) provided.
|
||||||
|
@ -14,4 +14,4 @@ contract C {
|
|||||||
// ----
|
// ----
|
||||||
// TypeError 5347: (72-76): Try can only be used with external function calls and contract creation calls.
|
// TypeError 5347: (72-76): Try can only be used with external function calls and contract creation calls.
|
||||||
// TypeError 2536: (119-128): Try can only be used with external function calls and contract creation calls.
|
// TypeError 2536: (119-128): Try can only be used with external function calls and contract creation calls.
|
||||||
// TypeError 4259: (176-183): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(address) provided.
|
// TypeError 4259: (176-183): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but type(address) provided.
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256[][10][] x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 constant h = type(S).typehash;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
bytes32 x = type(C).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9582: (29-45): Member "typehash" not found or not visible after argument-dependent lookup in type(contract C).
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
enum E {
|
||||||
|
VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(E).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9582: (63-79): Member "typehash" not found or not visible after argument-dependent lookup in type(enum C.E).
|
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256[][10][] x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 immutable h;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
h = type(S).typehash;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
enum E {
|
||||||
|
VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
E e;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (98-114): "typehash" cannot be used for structs with members of "enum C.E" type.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
fixed128x18 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (74-90): "typehash" cannot be used for structs with members of "fixed128x18" type.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
function(uint256) internal returns(uint256) f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (106-122): "typehash" cannot be used for structs with members of "function (uint256) returns (uint256)" type.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
mapping (uint256 => uint256) x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (91-107): "typehash" cannot be used for structs with members of "mapping(uint256 => uint256)" type.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
ufixed128x18 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (75-91): "typehash" cannot be used for structs with members of "ufixed128x18" type.
|
@ -0,0 +1,10 @@
|
|||||||
|
type T is uint256;
|
||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
T t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9518: (83-99): "typehash" cannot be used for structs with members of "T" type.
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public pure returns(bytes32) {
|
||||||
|
return type(S).typehash;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
S[] s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9298: (66-82): "typehash" cannot be used for recursive structs.
|
@ -0,0 +1,14 @@
|
|||||||
|
contract A {
|
||||||
|
struct S {
|
||||||
|
C.S[] s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
A.S s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 h = type(S).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9298: (119-135): "typehash" cannot be used for recursive structs.
|
@ -0,0 +1,15 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f1(S calldata s) public pure returns(bytes32 h) {
|
||||||
|
h = type(s).typehash; // should fail
|
||||||
|
}
|
||||||
|
|
||||||
|
function f3(S calldata s) public pure returns(bytes32 h) {
|
||||||
|
h = type(S).typehash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 4259: (134-135): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but struct C.S calldata provided.
|
@ -0,0 +1,15 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f1(S memory s) public pure returns(bytes32 h) {
|
||||||
|
h = type(s).typehash; // should fail
|
||||||
|
}
|
||||||
|
|
||||||
|
function f3(S calldata s) public pure returns(bytes32 h) {
|
||||||
|
h = type(S).typehash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 4259: (132-133): Invalid type for argument in the function call. An enum type, contract type, struct type or an integer type is required, but struct C.S memory provided.
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
bytes32 h = type(uint256).typehash;
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9582: (29-51): Member "typehash" not found or not visible after argument-dependent lookup in type(uint256).
|
@ -0,0 +1,11 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint256 x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public view returns(bytes32) { // can be pure
|
||||||
|
return type(S).typehash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning 2018: (58-155): Function state mutability can be restricted to pure
|
Loading…
Reference in New Issue
Block a user