Display human readable type name in conversion error message

This commit is contained in:
Ryan 2022-05-11 00:24:52 -05:00 committed by nishant-sachdeva
parent f2c930588c
commit 4b7ed2d47a
7 changed files with 113 additions and 13 deletions

View File

@ -1842,7 +1842,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
_functionCall.location(), _functionCall.location(),
ssl, ssl,
"Explicit type conversion not allowed from non-payable \"address\" to \"" + "Explicit type conversion not allowed from non-payable \"address\" to \"" +
resultType->toString() + resultType->humanReadableName() +
"\", which has a payable fallback function." "\", which has a payable fallback function."
); );
} }
@ -1856,9 +1856,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
5030_error, 5030_error,
_functionCall.location(), _functionCall.location(),
"Explicit type conversion not allowed from \"" + "Explicit type conversion not allowed from \"" +
argType->toString() + argType->humanReadableName() +
"\" to \"" + "\" to \"" +
resultType->toString() + resultType->humanReadableName() +
"\". To obtain the address of the contract of the function, " + "\". To obtain the address of the contract of the function, " +
"you can use the .address member of the function." "you can use the .address member of the function."
); );
@ -1867,9 +1867,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
9640_error, 9640_error,
_functionCall.location(), _functionCall.location(),
"Explicit type conversion not allowed from \"" + "Explicit type conversion not allowed from \"" +
argType->toString() + argType->humanReadableName() +
"\" to \"" + "\" to \"" +
resultType->toString() + resultType->humanReadableName() +
"\".", "\".",
result.message() result.message()
); );

View File

@ -110,6 +110,14 @@ util::Result<TypePointers> transformParametersToExternal(TypePointers const& _pa
return transformed; 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): MemberList::Member::Member(Declaration const* _declaration, Type const* _type):
@ -3090,6 +3098,19 @@ string FunctionType::canonicalName() const
return "function"; 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 FunctionType::toString(bool _short) const
{ {
string name = "function "; string name = "function ";
@ -3101,20 +3122,15 @@ string FunctionType::toString(bool _short) const
name += *contract->annotation().canonicalName + "."; name += *contract->annotation().canonicalName + ".";
name += functionDefinition->name(); name += functionDefinition->name();
} }
name += '('; name += toStringInParentheses(m_parameterTypes, _short);
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
name += ")";
if (m_stateMutability != StateMutability::NonPayable) if (m_stateMutability != StateMutability::NonPayable)
name += " " + stateMutabilityToString(m_stateMutability); name += " " + stateMutabilityToString(m_stateMutability);
if (m_kind == Kind::External) if (m_kind == Kind::External)
name += " external"; name += " external";
if (!m_returnParameterTypes.empty()) if (!m_returnParameterTypes.empty())
{ {
name += " returns ("; name += " returns ";
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it) name += toStringInParentheses(m_returnParameterTypes, _short);
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
name += ")";
} }
return name; return name;
} }

View File

@ -339,6 +339,7 @@ public:
std::string toString() const { return toString(false); } std::string toString() const { return toString(false); }
/// @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(); }
/// @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]`.
@ -1378,6 +1379,7 @@ public:
TypeResult unaryOperatorResult(Token _operator) const override; TypeResult unaryOperatorResult(Token _operator) const override;
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 toString(bool _short) const override; std::string toString(bool _short) 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; }

View File

@ -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".

View File

@ -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".

View File

@ -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).

View File

@ -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".