diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0b66f7ef3..5ff6f18f1 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3393,7 +3393,31 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "interfaceId") annotation.isPure = true; else if (magicType->kind() == MagicType::Kind::MetaType && memberName == "typehash") + { annotation.isPure = true; + auto accessedStructType = dynamic_cast(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 ( magicType->kind() == MagicType::Kind::MetaType && (memberName == "min" || memberName == "max") diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index bca79f555..37cb843e8 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -358,6 +358,7 @@ public: virtual std::string canonicalName() const { return toString(true); } virtual std::string humanReadableName() const { return toString(); } virtual std::string eip712TypeName() const { return encodingType()->toString(true); } + virtual bool isEIP712AllowedStructMemberType() const { return false; } /// @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, /// structs are given by canonical name like `ContractName.StructName[2]`. @@ -458,6 +459,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -503,6 +505,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; @@ -662,6 +665,8 @@ public: return nullptr; } + bool isEIP712AllowedStructMemberType() const override { return true; } + std::string richIdentifier() const override; bool operator==(Type const& _other) const override; @@ -700,6 +705,7 @@ public: bool leftAligned() const override { return true; } bool isValueType() 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); } MemberList::MemberMap nativeMembers(ASTNode const*) const override; @@ -728,6 +734,7 @@ public: bool leftAligned() const override { return false; } bool isValueType() const override { return true; } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool) const override { return "bool"; } u256 literalValue(Literal const* _literal) const override; @@ -865,6 +872,7 @@ public: u256 storageSize() const override; bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); } bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; std::string humanReadableName() const override; @@ -978,6 +986,7 @@ public: bool leftAligned() const override { solAssert(!isSuper(), ""); return false; } bool isValueType() 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 canonicalName() const override; @@ -1040,6 +1049,7 @@ public: u256 storageSize() const override; bool containsNestedMapping() const override; bool nameable() const override { return true; } + bool isEIP712AllowedStructMemberType() const override { return true; } std::string toString(bool _withoutDataLocation) const override; MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override; diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_const.sol b/test/libsolidity/syntaxTests/types/struct/typehash_const.sol new file mode 100644 index 000000000..e9f33f1d1 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_const.sol @@ -0,0 +1,7 @@ +contract C { + struct S { + uint256[][10][] x; + } + + bytes32 constant h = type(S).typehash; +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol b/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol new file mode 100644 index 000000000..22bad80aa --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_contract.sol @@ -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). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol b/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol new file mode 100644 index 000000000..670ef1ccf --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_enum.sol @@ -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). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol new file mode 100644 index 000000000..695ef07ac --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_enum.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol new file mode 100644 index 000000000..0b3c5b57b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_fixed128x18.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol new file mode 100644 index 000000000..7e2e5895c --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_function.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol new file mode 100644 index 000000000..27dd775e6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_mapping.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + mapping (uint256 => uint256) x; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9518: (92-108): "typehash" cannot be used for structs with members of "mapping(uint256 => uint256)" type. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol new file mode 100644 index 000000000..5393a30e8 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_ufixed128x18.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol b/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol new file mode 100644 index 000000000..5f46378c2 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_member_userdefined.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol b/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol new file mode 100644 index 000000000..fdca58e27 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_pure.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + uint256 x; + } + + function f() public pure returns(bytes32) { + return type(S).typehash; + } +} \ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol new file mode 100644 index 000000000..018411d8b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct.sol @@ -0,0 +1,9 @@ +contract C { + struct S { + S[] s; + } + + bytes32 h = type(S).typehash; +} +// ---- +// TypeError 9298: (68-84): "typehash" cannot be used for recursive structs. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol new file mode 100644 index 000000000..9f46255ed --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_recursive_struct_2.sol @@ -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: (121-137): "typehash" cannot be used for recursive structs. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol new file mode 100644 index 000000000..049bc46d5 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol new file mode 100644 index 000000000..9ba0bc761 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_struct_variable_2.sol @@ -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. diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol b/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol new file mode 100644 index 000000000..d6ff2d73d --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_uint256.sol @@ -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). diff --git a/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol b/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol new file mode 100644 index 000000000..85bad50b2 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/struct/typehash_viewpure.sol @@ -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