diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index ed9875fce..7f31fb56f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1842,7 +1842,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( _functionCall.location(), ssl, "Explicit type conversion not allowed from non-payable \"address\" to \"" + - resultType->toString() + + resultType->humanReadableName() + "\", which has a payable fallback function." ); } @@ -1856,9 +1856,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( 5030_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + - argType->toString() + + argType->humanReadableName() + "\" to \"" + - resultType->toString() + + resultType->humanReadableName() + "\". To obtain the address of the contract of the function, " + "you can use the .address member of the function." ); @@ -1867,9 +1867,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( 9640_error, _functionCall.location(), "Explicit type conversion not allowed from \"" + - argType->toString() + + argType->humanReadableName() + "\" to \"" + - resultType->toString() + + resultType->humanReadableName() + "\".", result.message() ); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 48e4afa51..c1333c28b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -110,6 +110,14 @@ util::Result transformParametersToExternal(TypePointers const& _pa return transformed; } +string toStringInParentheses(TypePointers const& _types, bool _short) +{ + return '(' + util::joinHumanReadable( + _types | ranges::views::transform([&](auto const* _type) { return _type->toString(_short); }), + "," + ) + ')'; +} + } MemberList::Member::Member(Declaration const* _declaration, Type const* _type): @@ -3090,6 +3098,19 @@ string FunctionType::canonicalName() const return "function"; } +string FunctionType::humanReadableName() const +{ + switch (m_kind) + { + case Kind::Error: + return "error " + m_declaration->name() + toStringInParentheses(m_parameterTypes, /* _short */ true); + case Kind::Event: + return "event " + m_declaration->name() + toStringInParentheses(m_parameterTypes, /* _short */ true); + default: + return toString(/* _short */ false); + } +} + string FunctionType::toString(bool _short) const { string name = "function "; @@ -3101,20 +3122,15 @@ string FunctionType::toString(bool _short) const name += *contract->annotation().canonicalName + "."; name += functionDefinition->name(); } - name += '('; - for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) - name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); - name += ")"; + name += toStringInParentheses(m_parameterTypes, _short); if (m_stateMutability != StateMutability::NonPayable) name += " " + stateMutabilityToString(m_stateMutability); if (m_kind == Kind::External) name += " external"; if (!m_returnParameterTypes.empty()) { - name += " returns ("; - for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it) - name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ","); - name += ")"; + name += " returns "; + name += toStringInParentheses(m_returnParameterTypes, _short); } return name; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 9b3080769..45e77a0d4 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -339,6 +339,7 @@ public: std::string toString() const { return toString(false); } /// @returns the canonical name of this type for use in library function signatures. virtual std::string canonicalName() const { return toString(true); } + virtual std::string humanReadableName() const { return toString(); } /// @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]`. @@ -1378,6 +1379,7 @@ public: TypeResult unaryOperatorResult(Token _operator) const override; TypeResult binaryOperatorResult(Token, Type const*) const override; std::string canonicalName() const override; + std::string humanReadableName() const override; std::string toString(bool _short) const override; unsigned calldataEncodedSize(bool _padded) const override; bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; } diff --git a/test/libsolidity/syntaxTests/conversion/explicit_conversion_error_to_bytes4.sol b/test/libsolidity/syntaxTests/conversion/explicit_conversion_error_to_bytes4.sol new file mode 100644 index 000000000..309dccabd --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/explicit_conversion_error_to_bytes4.sol @@ -0,0 +1,11 @@ +interface MyInterface { + error MyCustomError(uint256, bool); +} + +contract Test { + function test() public returns(bytes4) { + return bytes4(MyInterface.MyCustomError); + } +} +// ---- +// TypeError 9640: (143-176): Explicit type conversion not allowed from "error MyCustomError(uint256,bool)" to "bytes4". diff --git a/test/libsolidity/syntaxTests/conversion/explicit_conversion_event_to_bytes4.sol b/test/libsolidity/syntaxTests/conversion/explicit_conversion_event_to_bytes4.sol new file mode 100644 index 000000000..dd036791f --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/explicit_conversion_event_to_bytes4.sol @@ -0,0 +1,9 @@ +contract Test { + event MyCustomEvent(uint256); + + function test() public returns(bytes4) { + return bytes4(MyCustomEvent); + } +} +// ---- +// TypeError 9640: (111-132): Explicit type conversion not allowed from "event MyCustomEvent(uint256)" to "bytes4". diff --git a/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_error.sol b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_error.sol new file mode 100644 index 000000000..b13067e03 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_error.sol @@ -0,0 +1,28 @@ +interface MyInterface { + enum MyEnum { E1, E2 } + error CustomError1( + uint256, + bool, + bool[], + address payable, + MyInterface, + MyEnum, + function (string memory) external returns (uint) + ); +} + +contract Test { + function testFunction(string memory) external returns (uint) {} + + function test() public { + MyInterface instance = MyInterface(msg.sender); + bool[] calldata arr; + address payable addr; + bytes4(MyInterface.CustomEror1); + bytes4(MyInterface.CustomError1()); + bytes4(MyInterface.CustomError1(1, true, arr, addr, instance, MyInterface.MyEnum.E1, this.testFunction)); + address(MyInterface.CustomError1); + } +} +// ---- +// TypeError 9582: (495-518): Member "CustomEror1" not found or not visible after argument-dependent lookup in type(contract MyInterface). diff --git a/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_event.sol b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_event.sol new file mode 100644 index 000000000..62edf7de8 --- /dev/null +++ b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_event.sol @@ -0,0 +1,34 @@ +interface MyInterface { + enum MyEnum { E1, E2 } +} + +contract Test { + function testFunction(string memory) external returns (uint) {} + + event CustomEvent1( + uint256, + bool, + bool[], + address payable, + MyInterface, + MyInterface.MyEnum, + function (string memory) external returns (uint) + ); + + + function test() public { + MyInterface instance = MyInterface(msg.sender); + bool[] calldata arr; + address payable addr; + bytes4(CustomEvent1); + bytes4(CustomEvent1()); + bytes4(CustomEvent1(1, true, arr, addr, instance, MyInterface.MyEnum.E1, this.testFunction)); + address(CustomEvent1); + } +} +// ---- +// TypeError 9640: (502-522): Explicit type conversion not allowed from "event CustomEvent1(uint256,bool,bool[],address payable,contract MyInterface,enum MyInterface.MyEnum,function (string) external returns (uint256))" to "bytes4". +// TypeError 6160: (539-553): Wrong argument count for function call: 0 arguments given but expected 7. +// TypeError 9640: (532-554): Explicit type conversion not allowed from "tuple()" to "bytes4". +// TypeError 9640: (564-656): Explicit type conversion not allowed from "tuple()" to "bytes4". +// TypeError 9640: (666-687): Explicit type conversion not allowed from "event CustomEvent1(uint256,bool,bool[],address payable,contract MyInterface,enum MyInterface.MyEnum,function (string) external returns (uint256))" to "address".