diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index ee7a65004..6183493b4 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -578,3 +578,8 @@ MappingType const* TypeProvider::mapping(Type const* _keyType, Type const* _valu { return createAndGet(_keyType, _valueType); } + +UserDefinedValueType const* TypeProvider::userDefinedValueType(UserDefinedValueTypeDefinition const& _definition) +{ + return createAndGet(_definition); +} diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 6cdfdadc6..78b8378ca 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -201,6 +201,8 @@ public: static MappingType const* mapping(Type const* _keyType, Type const* _valueType); + static UserDefinedValueType const* userDefinedValueType(UserDefinedValueTypeDefinition const& _definition); + private: /// Global TypeProvider instance. static TypeProvider& instance() diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 0fe9a728f..c1163156a 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2533,6 +2533,36 @@ unsigned EnumType::memberValue(ASTString const& _member) const solAssert(false, "Requested unknown enum value " + _member); } +Type const& UserDefinedValueType::underlyingType() const +{ + Type const* type = m_definition.underlyingType()->annotation().type; + solAssert(type, ""); + return *type; +} + +string UserDefinedValueType::richIdentifier() const +{ + return "t_userDefinedValueType" + parenthesizeIdentifier(m_definition.name()) + to_string(m_definition.id()); +} + +bool UserDefinedValueType::operator==(Type const& _other) const +{ + if (_other.category() != category()) + return false; + UserDefinedValueType const& other = dynamic_cast(_other); + return other.definition() == definition(); +} + +string UserDefinedValueType::toString(bool /* _short */) const +{ + return "user defined type " + definition().name(); +} + +vector> UserDefinedValueType::makeStackItems() const +{ + return underlyingType().stackItems(); +} + BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const { if (auto tupleType = dynamic_cast(&_other)) @@ -2884,6 +2914,8 @@ string FunctionType::richIdentifier() const case Kind::GasLeft: id += "gasleft"; break; case Kind::Event: id += "event"; break; case Kind::Error: id += "error"; break; + case Kind::Wrap: id += "wrap"; break; + case Kind::Unwrap: id += "unwrap"; break; case Kind::SetGas: id += "setgas"; break; case Kind::SetValue: id += "setvalue"; break; case Kind::BlockHash: id += "blockhash"; break; @@ -3754,6 +3786,34 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons for (ASTPointer const& enumValue: enumDef.members()) members.emplace_back(enumValue.get(), enumType); } + else if (m_actualType->category() == Category::UserDefinedValueType) + { + auto& userDefined = dynamic_cast(*m_actualType); + members.emplace_back( + "wrap", + TypeProvider::function( + TypePointers{&userDefined.underlyingType()}, + TypePointers{&userDefined}, + strings{string{}}, + strings{string{}}, + FunctionType::Kind::Wrap, + false, /*_arbitraryParameters */ + StateMutability::Pure + ) + ); + members.emplace_back( + "unwrap", + TypeProvider::function( + TypePointers{&userDefined}, + TypePointers{&userDefined.underlyingType()}, + strings{string{}}, + strings{string{}}, + FunctionType::Kind::Unwrap, + false, /* _arbitraryParameters */ + StateMutability::Pure + ) + ); + } else if ( auto const* arrayType = dynamic_cast(m_actualType); arrayType && arrayType->isByteArray() diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 57f5201f6..b092628fb 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -174,7 +174,7 @@ public: enum class Category { Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array, ArraySlice, - FixedBytes, Contract, Struct, Function, Enum, Tuple, + FixedBytes, Contract, Struct, Function, Enum, UserDefinedValueType, Tuple, Mapping, TypeType, Modifier, Magic, Module, InaccessibleDynamic }; @@ -1082,6 +1082,53 @@ private: EnumDefinition const& m_enum; }; +/** + * The type of a UserDefinedValueType. + */ +class UserDefinedValueType: public Type +{ +public: + explicit UserDefinedValueType(UserDefinedValueTypeDefinition const& _definition): + m_definition(_definition) + {} + + Category category() const override { return Category::UserDefinedValueType; } + Type const& underlyingType() const; + UserDefinedValueTypeDefinition const& definition() const { return m_definition; } + + TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } + Type const* encodingType() const override { return &underlyingType(); } + TypeResult interfaceType(bool /* _inLibrary */) const override {return &underlyingType(); } + std::string richIdentifier() const override; + bool operator==(Type const& _other) const override; + + unsigned calldataEncodedSize(bool _padded) const override { return underlyingType().calldataEncodedSize(_padded); } + + bool leftAligned() const override { return underlyingType().leftAligned(); } + bool canBeStored() const override { return underlyingType().canBeStored(); } + u256 storageSize() const override { return underlyingType().storageSize(); } + bool isValueType() const override + { + solAssert(underlyingType().isValueType(), ""); + return true; + } + bool nameable() const override + { + solAssert(underlyingType().nameable(), ""); + return true; + } + + std::string toString(bool _short) const override; + std::string canonicalName() const override { solAssert(false, ""); } + std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } + +protected: + std::vector> makeStackItems() const override; + +private: + UserDefinedValueTypeDefinition const& m_definition; +}; + /** * Type that can hold a finite sequence of values of different types. * In some cases, the components are empty pointers (when used as placeholders). @@ -1150,6 +1197,8 @@ public: RIPEMD160, ///< CALL to special contract for ripemd160 Event, ///< syntactic sugar for LOG* Error, ///< creating an error instance in revert or require + Wrap, ///< customType.wrap(...) for user defined value types + Unwrap, ///< customType.unwrap(...) for user defined value types SetGas, ///< modify the default gas value for the function call SetValue, ///< modify the default value transfer for the function call BlockHash, ///< BLOCKHASH